The weakest link

This article was originally published in VSJ, which is now part of Developer Fusion.
Our previous articles on the GoF’s Design Patterns have tended to focus on patterns that deliver the most frequent benefits to modern .NET developers, such as the various factory patterns, State and Strategy. In this instalment, however, you’re going to get a good look at one of the lesser-used patterns, Chain of Responsibility (CoR).

The reason for this is that it is very easy to focus on the features and benefits of a pattern, but that’s actually only half of the story. There is another very important aspect that you really have to consider when working with patterns: the consequences. These are not always positive, and when combined with other aspects such as language implementation details, can make the usage of a pattern less desirable than it first appears.

The first section of the article will therefore focus on what the CoR pattern is, and how to use features such as the new .NET 2.0 System.Configuration types to implement a configurable, albeit deliberately simplistic, message handling system. Then comes the fun part; picking the pattern apart. This is not to say that the pattern is completely inappropriate for .NET developers; it’s just that CoR has some specific aspects that make it less appealing to .NET developers than it was, say, for classic C++ programmers a decade ago.

So without further ado, it’s time to meet the CoR.

The message handling system

Figure 1 shows a conceptual diagram for the message handling system.

Figure 1
Figure 1: An overview of the message handling system

The client sends in a message, which has to be routed to the correct handler. Currently, there are two types of message: a priority message which gets special treatment, and all other messages which are processed by a single message handler. However, it’s fairly easy to conceive that there might be additional requirements in the future, including the ability to stop spam from penetrating the system, and so on. Ideally, you’d like to be able to “hot plug” the new functionality into the server without having to modify the client in any way. This in turn tends to preclude adding all of the conditional logic for routing messages into a single object, as every new modification would require a rebuild of the server and (potentially) the client. It would also make testing that little bit harder.

Bring on the Chain of Responsibility

Solving the message handling problem can be achieved quite easily using the Chain of Responsibility pattern, which is briefly summarised by the GoF as follows:
“Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.”
Clearly, this pattern is once again focused on de-coupling two objects, the client and the handler, giving you the flexibility to substitute in a different handler depending on your requirements. However, this pattern also has another aspect to it: the ability to have one of many possible handlers process the request depending on the message matching some specified criteria. Figure 2 summarises these aspects of the CoR pattern.

Figure 2
Figure 2: The pluggable extensibility of the CoR pattern

Critically, and something that’s not mentioned in the GoF summary but which is described within the more detailed explanation of the pattern, each handler should operate without knowing about the internals of any other handler. With this in mind, and having taken a look at Figure 2, your programming mind might well be screaming “I need interface-based programming to achieve this.”

In fact, CoR is one of those cases where using an abstract base class that is then specialised for each handler adds some benefits. So let’s take a look at how you could use CoR to implement the message handling system.

Implementing the CoR

Each node in the chain should do two things:
  1. Handle the incoming message if the message matches some criteria, and
  2. Otherwise, forward the message on to the next item in the chain
The most obvious implementation of these requirements yields the UML diagram shown in Figure 3.

Figure 3
Figure 3: The UML class diagram for the CoR Pattern

The abstract Handler class would typically be implemented so that it contained the logic for calling the next item in the chain, allowing each concrete handler to simply perform its decision making/processing logic.

A specific benefit of this design is that neither the client, nor each handler, knows any information about the next item in the chain. All you have to do is write code to build the chain and pass a reference, of type Handler, back to the client. Clearly, you would use some form of Builder or Factory to make the chain.

To demonstrate the dynamic capabilities of the CoR pattern, let’s examine an implementation that loads the message handlers from a configuration file.

The base MessageHandler type

Clearly, all of our handlers must either expose the same interface or be derived from a common type, so let’s start by defining an abstract handler from which all other method handlers will derive:
namespace CorHandlers
{
	public abstract class
		MessageHandler
	{
		public MessageHandler Successor
			{ get; set; }
		public void HandleRequest(
			string msg)
		{
			bool handled =
				InternalHandleRequest(
				message);
			if (!handled && Successor
				!= null)
				Successor.HandleRequest(
					message);
		}
		protected abstract bool
			InternalHandleRequest(
			string msg);
	}
}
The specific reason for using an abstract base type in preference to an interface is that there is some common implementation code that all of the types need to share; namely the ability to forward requests down to the next element in the chain. The MessageHandler class implements its public HandleRequest method by calling down to an implementation function that the concrete handlers must provide. It will forward the request to the next item in the chain, assuming that there is one, depending on the response it gets back.

As a quick aside, note that this implementation of HandleRequest is based upon yet another design pattern: TemplateMethod. This involves delegating parts of an algorithm – in this case the InternalHandleRequest method that checks and handles the message – to a derived class, whilst retaining the rest of algorithm in the base class (namely, forwarding on to the next item in the chain).

This is a very common technique that is used throughout the .NET Framework – for example every ASP.NET developer has used it when writing a page.

A quick note on C# properties

The code given above is designed for use with the new C# 3 compiler, which is smart enough to provide a backing field for a property without you having to type it in yourself. Thus the Successor property is fully implemented in the MessageHandler class, and it is not abstract.

If you’re targeting C# 2.0, on the other hand, you would need to add your own private field and get and set its value explicitly in the property’s get and set blocks.

The concrete message handlers

The code for the concrete message handlers is:
namespace CorHandlers
{
	public class NoOpHandler :
		MessageHandler
	{
		protected override bool
			InternalHandleRequest(
			string msg)
		{
			return false;
			// Not handled!
		}
	}

	public class NormalMessageHandler :
		MessageHandler
	{
		protected override bool
			InternalHandleRequest(
			string msg)
		{
			MessageBox.Show(msg);
			return true; // handled
		}
	}

	public class PriorityMessageHandler
		: MessageHandler
	{
		protected override bool
			InternalHandleRequest(
			string m)
		{
			if (message.ToLower().
				StartsWith(“priority”))
			{
				MessageBox.Show(message,
					“Priority Message”);
				return true; // handled
			}
			return false;
	// !handled, so continue down chain
		}
	}
}
Note that these are intentionally very simple handlers: the focus here is on the pattern, not the code. The NormalHandler simply displays any message using a MessageBox, and returns true to indicate that the message has been handled.

PriorityHandler, on the other hand, performs a check to see whether a message actually is a priority message. If it is, then it handles it; otherwise it returns false to indicate that the message should continue down the chain.

The NoOpHandler

There is a third handler defined: NoOpHandler. NoOpHandler does nothing, but it enables one simplification in the client code. Consider the client code, which might look something like this:
MessageHandler handler =
	MessageHandlerFactory.GetHandler();
...
handler.HandleRequest();
NoOpHandler allows the client to be coded without having to make a check for null, because even if you don’t want to load any “real” handlers for some reason, your factory can always return a NoOpHandler. This is conceptually very similar to the idea that methods / properties that return array, for example, should return an empty array if there’s no data rather than null.

Implementing a configurable chain

One the core benefits of the CoR pattern can be realised by allowing the chain to be built dynamically, based on configuration information. This allows new handlers to be introduced without rebuilding any code. The following listing for the application configuration file shows an example of this behaviour:
<?xml version=”1.0” encoding=”utf-8” ?>
<configuration>
	<configSections>
		<section name=”messageHandlers”
type=”DynamicCOR.MessageHandlerSection
			, DynamicCOR” />
	</configSections>
<!- Order is important!! ->
<messageHandlers>
	<messageHandler name=”PriorityHandler”
type=”CorHandlers.PriorityMessageHandler,
			CorHandlers” />
	<messageHandler
		name=”NormalHandler”
type=”CorHandlers.NormalMessageHandler,
			CorHandlers” />
	</messageHandlers>
</configuration>
You’ll note the two handlers are being specified in a custom <messageHandlers> element in the configuration file. Whilst perhaps not directly relevant to a discussion of the CoR pattern, you might be interested in the ease with which you can create custom configuration sections in .NET 2.0 and beyond; the complete code for reading this configuration section is:
using System;
using System.Configuration;

namespace DynamicCOR
{
	public class MessageHandlerSection
		: ConfigurationSection
	{
		public MessageHandlerSection()
		{
			base.Properties.Add(prop);
		}

		[ConfigurationProperty(“”,
			IsDefaultCollection = true)]
		public MessageHandlerCollection
			Handlers
		{
			get { return (
				MessageHandlerCollection
				)base[prop]; }
		}

		static readonly
			ConfigurationProperty prop =
			new ConfigurationProperty(“”,
			typeof(
			MessageHandlerCollection),
			null,
			ConfigurationPropertyOptions.
			IsDefaultCollection);
	}

	public class MessageHandlerElement
		: ConfigurationElement
	{
		[ConfigurationProperty(“name”,
			IsKey = true,
			IsRequired = true)]
		public string Name
		{
			get { return
				(string)base[“name”]; }
			set { base[“name”] = value;}
		}

		[ConfigurationProperty(“type”,
			IsRequired = true)]
		public string TypeName
		{
			get { return
				(string)base[“type”]; }
			set { base[“type”] = value;}
		}
	}

	[ConfigurationCollection(
		typeof(MessageHandlerElement),
		AddItemName = “messageHandler”,
		CollectionType =
	ConfigurationElementCollectionType.
		BasicMapAlternate)]
	public class
		MessageHandlerCollection :
		ConfigurationElementCollection
	{
		protected override
			ConfigurationElement
			CreateNewElement()
		{
			return new
				MessageHandlerElement();
		}

		protected override object
			GetElementKey(
			ConfigurationElement element)
		{
			return ((
				MessageHandlerElement
				)element).Name;
		}
	}
}

The chain factory

The client code presented earlier exploited a factory to make the chain on its behalf. A simple chain factory implementation is now shown:
public static class
	MessageHandlerFactory
{
	public static MessageHandler
		GetHandler()
	{
		Configuration config =
			ConfigurationManager.
			OpenExeConfiguration(
			ConfigurationUserLevel.None);
		MessageHandlerSection mhs =
		(MessageHandlerSection)config.
		GetSection(“messageHandlers”);
		MessageHandler mh = null;
		foreach (MessageHandlerElement 
			ele in mhs.Handlers)
		{
			Type t = Type.GetType(
				ele.TypeName);
			MessageHandler temp =
				(MessageHandler
	)Activator.CreateInstance(t);
			AddHandlerToChain(ref mh,
				temp);
		}

		// Append a NullHandler to
		// ensure that the client
		// doesn’t have to check for
		// nulls
		if (mh == null)
			AddHandlerToChain(ref mh,
			new NoOpHandler());
		return mh;
	}

	private static void
		AddHandlerToChain(
		ref MessageHandler mh,
		MessageHandler temp)
	{
		if (mh == null)
		{
			mh = temp;
		}
		else
		{
			MessageHandler tail = mh;
			while(tail.Successor != null)
				tail = tail.Successor;
			tail.Successor = temp;
		}
	}
}
The simplified factory processes the configuration file and then builds the chain, appending each MessageHandler that it finds in the file. Note that it returns a NoOpHandler if the chain is empty, in order to simplify the client code as previously mentioned.

The factory code has also been separated out from the configuration section handler to make it easier to follow, but you could (would, probably?) combine the two into a single class to make it easier to work with.

The unaware client

The critical thing to note is that the client code only knows about the abstract MessageHandler class and the factory. All the client does is use the factory to obtain a MessageHandler reference. It then calls the HandleRequest method on the returned MessageHandler reference and the job is done. The client has no idea that a chain of handlers might be involved. In fact, it has no knowledge which specific handler processes the request, if any. Now that’s cool, very extensible and undoubtedly the real benefit of the CoR pattern.

CoR looks a little bit like the Decorator (or even the Proxy) pattern, in that the client obtains a reference – typically via a factory – to something that might be a chain of objects. However, these patterns differ massively in their intent. Both Decorator and Proxy provide additive features to an object: in essence for these patterns there is always one “ultimate handler”, with a bunch of extra “hangers on” that want to chip in with some additional functionality.

In the CoR pattern there are many handlers chained together, with just one of them taking action. Each handler is evaluated in order, and if it determines that it should handle the request, it does. Otherwise, it passes the request on to the next item in the chain.

Digging deeper

By now you should have a pretty clear understanding of the CoR pattern, and you might even be thinking that it looks interesting. However, at the beginning of the article I said that it’s important to consider the consequences of using a design pattern, and CoR on .NET is a nice example to poke around with.

CoR is really nothing more than a conditional if{} else{} construct expressed using types. The implementation above could effectively be rewritten (in pseudo-C#) as:

string message = ...;
if( message.StartsWith( “priority” ) )
	// PriorityHandler
{}
else
	// NormalHandler always handles
	// requests
{}
If you were to add in the notional SpamHandler, you would get:
string message = ...;
if( IsSpam( message ) ) // SpamHandler
{}
else if( message.StartsWith(
	“priority” ) ) // PriorityHandler
{}
else // NormalHandler always handles
	// requests
{}

Performance and testing

The thing to remember with CoR is that adding extra handlers will slow down the processing for each request. This is something that you pick up immediately when writing code, but it’s a little less obvious when the chain is constructed dynamically. It’s not a major concern, because the chains are normally quite short: just be careful.

It’s perfectly possible to unit test a CoR handler, and even chains of handlers. However, you have to remember that if you decide to allow chains to be built dynamically, and especially when using configuration-based chains, then testing gets much more interesting.

For example, there was a small but critically important comment in the listing for the application configuration file. It reads:

<!-- order is important -->
Simply put, swapping the order of the handlers completely changes the behaviour of the processing in exactly the same way that changing the order of an if{} else{} conditional block does. The gotcha here is that whilst you, as a programmer can clearly understand that, a systems administrator might not know that the <messageHandlers> block is order-specific and implemented using CoR. Thus a system that passes your tests perfectly in development might fail on a server where the configuration has been modified without your knowledge.

One potential solution to this problem is to assign a priority value to the handlers, with a factory implementation that then utilises that value to order the handlers. Assuming that the administrators understand your prioritisation system (is 1 higher or lower than 10, for example?) they still have the capability to remove or add handlers that you weren’t expecting.

Note this is not a problem that is specific to CoR, but is common whenever code is loaded and executed conditionally, or whenever rules are expressed outside of compiled code; it’s just the normal trade-off between flexibility and testability.

Implicit receivers and unhandled requests

Similarly, receipt cannot be guaranteed by any specific handler, because a new handler (the SpamHandler, for example) might be added into the chain ahead of the normal recipient and might consume a request that would normally have been processed further down the chain. This can certainly be a very positive consequence, as spammers might realise that pre-pending the word “Priority” on to the message gets attention. It’s also right at the heart of the loose coupling that CoR offers.

Currently, the message handling system guarantees to handle all requests because the NormalHandler is last in the chain and performs a default action; it is, essentially, an else {} block. However, it is perfectly possible to construct a chain of handlers where there is no default handler, and consequently incoming requests can remain unhandled. If you’re designing a system that uses CoR, you should consider adding a default handler to the end of the chain that logs the fact that an unhandled message has arrived.

What about using multiple handlers to respond to a call?

CoR is very explicit in its intent: one handler, and only one handler, should deal with a request. Now that’s not to say that you can’t tweak your code to utilise multiple handlers, but if you do then you’re no longer implementing CoR and should consider a different approach.

A good example of this is how WPF deals with routed events. Events in WPF tend to tunnel down the element tree, or bubble up, because as WPF developers you need the ability to be able to centralise event handling, or even to stop an event from being raised by a child element. WPF could easily have been designed to use CoR to deal with event routing, especially as the chain is pre-formed out of the natural hierarchy of the element tree, but the WPF team knew that you’d want to handle events in multiple places. Consequently, they chose to create an EventRoute object that builds an internal list of nodes that might want to respond to the event, and then have it iterate over that list invoking the handler as necessary. In general terms, you should be thinking of using an Iterator whenever you need multiple handlers to deal with a request.

The single inheritance trap

The simple message handling system that’s been presented in this article exploits one key feature that makes it easy to write new handlers: they all derive from the MessageHandler class. This base class contains the code for routing on requests to the next handler in the chain, ensuring that each handler need only override the InternalHandleRequest method. Unfortunately, you’re not always going to be that lucky. Anyone who remembers Microsoft Foundation Class Library (MFC), and who then moved on to Windows Forms programming, will almost certainly have missed MFC’s Doc/View/Frame architecture. Simply put, this helped MFC developers separate the data (Document) from its onscreen representation (the View), which was in turn held inside a Frame (either an MDI child window or a main window).

The clever feature of MFC was that it routed commands, which were typically generated by the user interacting with a menu or toolbar on the main window, through to the relevant document, view or frame window, as shown in Figure 4.

Figure 4
Figure 4: A simplified view of MFC-like command routing

The basic premise was that each item assumed responsibility for the different incoming commands, and the beauty of this approach was that you could effectively map event handling functionality generated on the main window to non-visual elements, without introducing a dependency in the code. In other words, it looks just like a CoR, although it has to be noted that later versions of MFC supported the idea of multiple items handling a single command. So could you reproduce this using CoR and Windows Forms? Indeed you can, but there is a downside: unlike unmanaged C++, .NET languages such as C# and Visual Basic only support single inheritance. Since your MainForm class would already derive from System.Windows.Forms.Form and your View class would probably derive from System.Windows.Forms.Control or one of its sub-classes, you wouldn’t be able to derive from an abstract class such as the MessageHandler presented earlier. This means that unless there was already a natural chain in place, you’d either have to externalise the chain from the objects or have each and every type have its own Successor implementation. Consequently, you’re much more likely to take the same approach that the WPF team took, and have each type implement an interface and then simply build an array or list and iterate through it externally.

This is, in fact, one of the primary reasons that CoR is not actually that popular in .NET.

Conclusion

Chain of Responsibility is an interesting and beneficial design pattern, and at first glance it appears to have some very useful benefits, ranging from its support for dynamically generated handlers to its very loose coupling between the client initiator and the message handler. However, as you’ve seen, there are consequences and limitations to using CoR that have to be taken into account when you opt to use it. And that was ultimately the purpose of this article. To remind you that, when you apply a pattern to a problem and no matter which pattern it is, there are going to be consequences. Some of them are good and some of them less so; but they are there all the same.


Dave Wheeler is a freelance consultant and software author, working primarily with Microsoft .NET. He delivers training courses with DevelopMentor, helps moderate various Microsoft forums, and is a regular speaker at DevWeek and other conferences. He can be contacted at [email protected].

You might also like...

Comments

About the author

Dave Wheeler United Kingdom

Dave Wheeler is a freelance instructor and consultant who specialises in .NET application development. He’s a moderator on Microsoft’s ASP.NET and Silverlight forums and is a regular speaker at ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Computer Science is no more about computers than astronomy is about telescopes.” - E. W. Dijkstra