Chain Of Command And Passing Parameters
One of the more useful patterns that I’ve used quite frequently is a version of Chain of Responsibility that integrates with the Command pattern. In a classic CoR, the idea is that only one component in the chain handles the request and then execution flows out of the chain. In a CoC pattern, the idea is that the execution flows through the entire chain.
I like Shahan Khatchadourian’s description of this pattern:
When programming, certain sections of code can sometimes be viewed as a workflow or preset sequence of tasks or commands. This can considered to be the design pattern called Chain of Command…
There are two key problems that this pattern solves that make it immensely useful in everyday programming (it’s a bit surprising that dofactory’s listing of CoR lists the frequency of use as a 2/5).
The first problem that it solves is extensibility. By implementing the chain as a list of abstract types (Command or Validator or whatever), using reflection (one way or another), you can build a list of concrete commands, giving each element in the chain a chance of working on the input request. One example of how I use this is to implement validation where I might have an abstract base class called Validator. To build the chain of validators, one very quick and easy solution is to reflect on the assembly and simply find all of the classes which implement Validator (additional complexity can be added as necessary, such as supporting validators in external assemblies or different groupings of validators).
The second (related) problem that it solves is excessively large blocks of if statements. In a validation example, you can imagine that if it were written in-line, each validation rule would essentially map to an if statement in a large block. In a way, it’s a very useful pattern for exchanging a tiny bit of performance and memory for more modular organization of logic. Without the CoC pattern, adding a new validation rule would mean adding another if block – yuck! Using CoC with reflection, we can simply add another class which inherits Validator to our project and count on the component building the chain to find our class and add it to the chain.
Here is a very simple, barebones implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<span style="font-family: Lucida Console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// A simple command chain factory that doesn't do wiring.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public static class </span><span style="color: #000000;">SimpleCommandChainFactory</span> <span style="color: #000000;">{</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Creates a simple list of commands to execute using reflection.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public static </span><span style="color: #808000;">List</span><span style="color: #000000;"><Command> Create()</span> <span style="color: #000000;">{</span> <span style="color: #000000;">var commands = </span><span style="color: #0000ff;">new </span><span style="color: #808000;">List</span><span style="color: #000000;"><Command>();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #808000;">Type</span><span style="color: #000000;">[] types = </span><span style="color: #808000;">Assembly</span><span style="color: #000000;">.GetExecutingAssembly().GetTypes();</span> <span style="color: #808000;">Type </span><span style="color: #000000;">commandType = </span><span style="color: #0000ff;">typeof </span><span style="color: #000000;">(Command);</span></span> <span style="font-family: Lucida Console;"> <span style="color: #0000ff;">foreach </span><span style="color: #000000;">(</span><span style="color: #808000;">Type </span><span style="color: #000000;">type </span><span style="color: #0000ff;">in </span><span style="color: #000000;">types)</span> <span style="color: #000000;">{</span> <strong><span style="color: #0000ff;">if </span><span style="color: #000000;">(!type.IsSubclassOf(commandType))</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">continue</span><span style="color: #000000;">;</span> <span style="color: #000000;">}</span> </strong> <span style="color: #000000;">MemberInitExpression init = </span><span style="color: #808000;">Expression</span><span style="color: #000000;">.MemberInit(</span> <span style="color: #808000;">Expression</span><span style="color: #000000;">.New(type), </span><span style="color: #0000ff;">new </span><span style="color: #000000;">MemberBinding[</span><span style="color: #800080;">0</span><span style="color: #000000;">]);</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">Command command = </span><span style="color: #808000;">Expression</span><span style="color: #000000;">.Lambda<Func<Command>>(init)</span> <span style="color: #000000;">.Compile().Invoke();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">commands.Add(command);</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">commands = commands.OrderBy(c => c.Priority).ToList();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #0000ff;">return </span><span style="color: #000000;">commands;</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
The code checks to see if a type if a sub-type of Command and, if so, creates an instance and puts it on the chain. The commands could then be executed like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">internal class </span><span style="color: #000000;">Program</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">private static void </span><span style="color: #000000;">Main(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">[] args)</span> <span style="color: #000000;">{</span> <span style="color: #808000;">List</span><span style="color: #000000;"><Command> commands = SimpleCommandChainFactory.Create();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">// Execute each command.</span> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(Command command </span><span style="color: #0000ff;">in </span><span style="color: #000000;">commands)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">command.Execute();</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
In this case, I’m not passing in data or checking for stop conditions (which might be useful in a validation scenario where the first failure stops processing). To do so, you could simply pass in a single instance of some context class to each command when executing and check to see if the stop condition is true after the execute call (and break out of the for-loop).
While this pattern is immensely useful any time you find a big if or switch block that’s particularly volatile, one problem that I’ve found with this pattern is passing parameters between two elements in the chain. Ideally, no element in the chain should have a dependency on another element in the chain. We want to decouple each of the elements to make it easier to build the chain dynamically. What this means is that no element should directly set values on another element in the chain. In essensce, to emulate the functionality of DependencyObject and DependencyProperty that we find in WF and WPF. (Why not just use WF then? Complexity and performance.)
At least two solutions come to mind. The first is to pass a context with a dictionary through each element of the chain. This would allow each element to place an output value into the dictionary and downstream components to pull these values out. The downside of this approach is that unless you force everything into one value type (i.e. serialize to an XML string?), you can’t really pass strongly typed data and now you’re keyed by strings (or whatever value type) which you need to have know about in order to retrieve the value.
A second approach would be to leverage DependencyObject and DependencyProperty. While this sounds good in principle, it requires a mess of code to accomplish in your own code with your own objects. Not only that, it seems to be overkill since many times, you don’t need the full capabilities of the dependency system – you just want to pass a value downstream in a nice, strongly typed manner.
(There is a third approach using thread local storage, but this is probably an even worse option than the first since it wouldn’t be very accessible to most developers and it doesn’t really address the issue at hand.)
In the past, I’ve relied on the dictionary based approach. While it wasn’t ideal, it was the simplest solution that got the job done. Deep down, I always hated this approach because I didn’t like having to know the keys and having to know how to cast the results retrieved from the dictionary. However, I recently came up with a much better solution to this issue: dynamically wired events.
We introduce two attribute classes which we can use to identify our event publishers and event subscribers. For brevity, I’ll only show the publisher attribute (they are pretty much the same in this implementation):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<span style="font-family: Lucida Console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Attribute used to identify event publishers.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #000000;">[AttributeUsage(AttributeTargets.Event)]</span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">EventPublisherAttribute : </span><span style="color: #808000;">Attribute</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">private readonly string </span><span style="color: #000000;">_eventName;</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Initializes a new instance of the <see cref="EventPublisherAttribute"/> class.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <param name="eventName">Name of the event.</param></span> <span style="color: #0000ff;">public </span><span style="color: #000000;">EventPublisherAttribute(</span><span style="color: #0000ff;">string </span><span style="color: #000000;">eventName)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">_eventName = eventName;</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Gets the name of the event.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <value>The name of the event.</value></span> <span style="color: #0000ff;">public string </span><span style="color: #000000;">EventName</span> <span style="color: #000000;">{</span> <span style="color: #000000;">get { </span><span style="color: #0000ff;">return </span><span style="color: #000000;">_eventName; }</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
The only difference between the two in this case is the AttributeUsageAttribute. In the case of the subscriber, we want it to apply to methods, not events. Next, we need to apply these attributes to our concrete command types that we’re going to chain. For this example, let’s say that the first item in the chain generates a GUID key that the rest of the items in the chain also need to use:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<span style="font-family: Lucida Console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Generates a GUID that may be needed by the rest of the chain.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">GenerateKeyCommand : Command</span> <span style="color: #000000;">{</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Raised when a key is generated;</span> <span style="color: #008000;">/// </summary></span> <span style="color: #000000;"><strong>[EventPublisher(EventNames.KeyGenerated)]</strong></span> <span style="color: #0000ff;">public event </span><span style="color: #000000;">EventHandler<</span><span style="color: #808000;">EventArgs</span><span style="color: #000000;"><Guid>> KeyGenerated;</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Executes this instance.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public override void </span><span style="color: #000000;">Execute()</span> <span style="color: #000000;">{</span> <span style="color: #000000;">Guid key = Guid.NewGuid();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #808000;">Console</span><span style="color: #000000;">.Out.WriteLine(</span><span style="color: #ff00ff;">"From GenerateKeyCommand: {0}"</span><span style="color: #000000;">, key);</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">OnKeyGenerated(key);</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Gets the priority. A lower value indicates higher priority.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <value>The priority.</value></span> <span style="color: #0000ff;">public override int </span><span style="color: #000000;">Priority</span> <span style="color: #000000;">{</span> <span style="color: #000000;">get { </span><span style="color: #0000ff;">return </span><span style="color: #800080;">1</span><span style="color: #000000;">; }</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Raises the key generated event.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <param name="key">The key.</param></span> <span style="color: #0000ff;">private void </span><span style="color: #000000;">OnKeyGenerated(Guid key)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if</span><span style="color: #000000;">(KeyGenerated != </span><span style="color: #0000ff;">null</span><span style="color: #000000;">)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">KeyGenerated(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">, </span><span style="color: #0000ff;">new </span><span style="color: #808000;">EventArgs</span><span style="color: #000000;"><Guid>(key));</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
As you can see, it’s pretty standard stuff, with the exception of the additional attribute on the event. Downstream, we want to handle these events in other commands:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<span style="font-family: Lucida Console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Simple command just for demonstration purposes.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">DoSomethingWithKeyCommand : Command</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">private </span><span style="color: #000000;">Guid _key;</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Executes this instance.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public override void </span><span style="color: #000000;">Execute()</span> <span style="color: #000000;">{</span> <span style="color: #808000;">Console</span><span style="color: #000000;">.Out.WriteLine(</span><span style="color: #ff00ff;">"From DoSomethingWithKeyCommand: {0}"</span><span style="color: #000000;">, _key);</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Gets the priority. A lower value indicates higher priority.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <value>The priority.</value></span> <span style="color: #0000ff;">public override int </span><span style="color: #000000;">Priority</span> <span style="color: #000000;">{</span> <span style="color: #000000;">get { </span><span style="color: #0000ff;">return </span><span style="color: #800080;">100</span><span style="color: #000000;">; }</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <strong><span style="color: #000000;">[EventSubscriber(EventNames.KeyGenerated)]</span> </strong> <span style="color: #0000ff;">private void </span><span style="color: #000000;">HandleKeyGenerated(</span><span style="color: #0000ff;">object </span><span style="color: #000000;">sender, </span><span style="color: #808000;">EventArgs</span><span style="color: #000000;"><Guid> e)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">_key = e.</span><span style="color: #008080;">Data</span><span style="color: #000000;">;</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
You can see that in the event handler method, we just grab the value from the event arguments and set it on a local variable for use when Execute() is called.
Now the trick is to wire these events up using reflection to avoid creating the direct dependency between the different elements in the chain. Spring.NET offers one way to do this using declarative events, however, it should be noted that it only works with singleton objects (this bit me in the butt until I figured it out). Depending on the nature of your elements in the chain, that may or may not be sufficient for you. If you need new instances every time, then we can accomplish this ourselves using a bit of reflection.
(Note that none of the code that follows has been optimized; there are a few caching opportunities to take advantage of to cut down on some of the reflection calls.)
The first step is to modify the factory method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<span style="font-family: Lucida Console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Creates a command chain using reflection.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <returns></returns></span> <span style="color: #0000ff;">public static </span><span style="color: #808000;">List</span><span style="color: #000000;"><Command> Create()</span> <span style="color: #000000;">{</span> <span style="color: #808000;">List</span><span style="color: #000000;"><Command> commands = </span><span style="color: #0000ff;">new </span><span style="color: #808000;">List</span><span style="color: #000000;"><Command>();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #808000;">Type</span><span style="color: #000000;">[] types = </span><span style="color: #808000;">Assembly</span><span style="color: #000000;">.GetExecutingAssembly().GetTypes();</span> <span style="color: #808000;">Type </span><span style="color: #000000;">commandType = </span><span style="color: #0000ff;">typeof </span><span style="color: #000000;">(Command);</span></span> <span style="font-family: Lucida Console;"> <strong><span style="color: #808000;">Dictionary</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><EventCoupling>> eventSources</span> <span style="color: #000000;">= </span><span style="color: #0000ff;">new </span><span style="color: #808000;">Dictionary</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><EventCoupling>>();</span> </strong> <strong> <span style="color: #808000;">Dictionary</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><MethodCoupling>> eventTargets</span> <span style="color: #000000;">= </span><span style="color: #0000ff;">new </span><span style="color: #808000;">Dictionary</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><MethodCoupling>>();</span></strong></span> <span style="font-family: Lucida Console;"> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(</span><span style="color: #808000;">Type </span><span style="color: #000000;">type </span><span style="color: #0000ff;">in </span><span style="color: #000000;">types)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if</span><span style="color: #000000;">(!type.IsSubclassOf(commandType))</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">continue</span><span style="color: #000000;">;</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">MemberInitExpression init = </span><span style="color: #808000;">Expression</span><span style="color: #000000;">.MemberInit(</span> <span style="color: #808000;">Expression</span><span style="color: #000000;">.New(type), </span><span style="color: #0000ff;">new </span><span style="color: #000000;">MemberBinding[</span><span style="color: #800080;">0</span><span style="color: #000000;">]);</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">Command command = </span><span style="color: #808000;">Expression</span><span style="color: #000000;">.Lambda<Func<Command>>(init)</span> <span style="color: #000000;">.Compile().Invoke();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">commands.Add(command);</span></span> <span style="font-family: Lucida Console;"> <strong><span style="color: #000000;">BuildHandlerCache(command, eventTargets, </span> <span style="color: #000000;">type.GetMethods(_methodFlags));</span> </strong> <strong><span style="color: #008000;">// Parse the events.</span> <span style="color: #808000;">EventInfo</span><span style="color: #000000;">[] events = type.GetEvents(</span> <span style="color: #000000;">BindingFlags.Public | BindingFlags.Instance);</span></strong></span> <span style="font-family: Lucida Console;"><strong> <span style="color: #0000ff;">if</span><span style="color: #000000;">(events.Length == </span><span style="color: #800080;">0</span><span style="color: #000000;">)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">continue</span><span style="color: #000000;">; </span> <span style="color: #000000;">}</span></strong></span> <span style="font-family: Lucida Console;"><strong> <span style="color: #000000;">BuildEventCache(command, eventSources, events);</span></strong> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;"><strong>WireEvents(eventSources, eventTargets);</strong></span></span> <span style="font-family: Lucida Console;"> <span style="color: #000000;">commands = commands.OrderBy(c => c.Priority).ToList();</span></span> <span style="font-family: Lucida Console;"> <span style="color: #0000ff;">return </span><span style="color: #000000;">commands;</span> <span style="color: #000000;">}</span></span> |
We create two caches as we iterate through the types to hold the events and handler methods that we encounter as we iterate the types and as a final step, we wire the events together from the caches. The cache building logic is fairly straightforward:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
<span style="font-family: Lucida console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Builds the handler cache.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <param name="command">The command.</param></span> <span style="color: #008000;">/// <param name="eventTargets">The event targets.</param></span> <span style="color: #008000;">/// <param name="methods">The methods.</param></span> <span style="color: #0000ff;">private static void </span><span style="color: #000000;">BuildHandlerCache(</span> <span style="color: #000000;">Command command, </span> <span style="color: #000000;">IDictionary<</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><MethodCoupling>> eventTargets, </span> <span style="color: #000000;">IEnumerable<</span><span style="color: #808000;">MethodInfo</span><span style="color: #000000;">> methods)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(</span><span style="color: #808000;">MethodInfo </span><span style="color: #000000;">method </span><span style="color: #0000ff;">in </span><span style="color: #000000;">methods)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">EventSubscriberAttribute[] subscriberAttributes =</span> <span style="color: #000000;">(EventSubscriberAttribute[])</span> <span style="color: #000000;">method.GetCustomAttributes(</span> <span style="color: #0000ff;">typeof</span><span style="color: #000000;">(EventSubscriberAttribute), </span><span style="color: #0000ff;">false</span><span style="color: #000000;">);</span></span> <span style="font-family: Lucida console;"> <span style="color: #0000ff;">if </span><span style="color: #000000;">(subscriberAttributes.Length == </span><span style="color: #800080;">0</span><span style="color: #000000;">)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">continue</span><span style="color: #000000;">;</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida console;"> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(EventSubscriberAttribute attribute </span><span style="color: #0000ff;">in </span><span style="color: #000000;">subscriberAttributes)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if</span><span style="color: #000000;">(!eventTargets.ContainsKey(attribute.EventName))</span> <span style="color: #000000;">{</span> <span style="color: #000000;">eventTargets[attribute.EventName] = </span><span style="color: #0000ff;">new </span><span style="color: #808000;">List</span><span style="color: #000000;"><MethodCoupling>();</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida console;"> <span style="color: #000000;">eventTargets[attribute.EventName].Add(</span> <span style="color: #0000ff;">new </span><span style="color: #000000;">MethodCoupling(method, command));</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida console;"><span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Builds the event caches.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #008000;">/// <param name="command">The command.</param></span> <span style="color: #008000;">/// <param name="eventSources">The event sources.</param></span> <span style="color: #008000;">/// <param name="events">The events.</param></span> <span style="color: #0000ff;">private static void </span><span style="color: #000000;">BuildEventCache(</span> <span style="color: #000000;">Command command,</span> <span style="color: #000000;">IDictionary<</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><EventCoupling>> eventSources, </span> <span style="color: #000000;">IEnumerable<</span><span style="color: #808000;">EventInfo</span><span style="color: #000000;">> events)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(</span><span style="color: #808000;">EventInfo </span><span style="color: #000000;">eventInfo </span><span style="color: #0000ff;">in </span><span style="color: #000000;">events)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">EventPublisherAttribute[] publisherAttributes =</span> <span style="color: #000000;">(EventPublisherAttribute[])</span> <span style="color: #000000;">eventInfo.GetCustomAttributes(</span> <span style="color: #0000ff;">typeof </span><span style="color: #000000;">(EventPublisherAttribute), </span><span style="color: #0000ff;">false</span><span style="color: #000000;">);</span></span> <span style="font-family: Lucida console;"> <span style="color: #0000ff;">if</span><span style="color: #000000;">(publisherAttributes.Length == </span><span style="color: #800080;">0</span><span style="color: #000000;">)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">continue</span><span style="color: #000000;">;</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida console;"> <span style="color: #0000ff;">foreach </span><span style="color: #000000;">(EventPublisherAttribute attribute </span><span style="color: #0000ff;">in </span><span style="color: #000000;">publisherAttributes)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if</span><span style="color: #000000;">(!eventSources.ContainsKey(attribute.EventName))</span> <span style="color: #000000;">{</span> <span style="color: #000000;">eventSources[attribute.EventName] = </span><span style="color: #0000ff;">new </span><span style="color: #808000;">List</span><span style="color: #000000;"><EventCoupling>();</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida console;"> <span style="color: #000000;">eventSources[attribute.EventName].Add(</span> <span style="color: #0000ff;">new </span><span style="color: #000000;">EventCoupling(eventInfo, command));</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span></span> |
The gist of it is that we want to iterate through the events and the methods, find the ones with the attributes, map them to instances of commands, and throw them into a dictionary. As you can see, the dictionary values are generic lists on both sides; this means that a single event can fire multiple event names and a single handler method can handle multiple events (as long as the method input types are the same). This may or may not be useful in any given scenario, but it’s easy enough to rewrite this to make it a bit simpler if it’s not required.
Finally, we need to wire the events together in the chain after it’s created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">private static void </span><span style="color: #000000;">WireEvents( </span><span style="color: #003300;"> </span><span style="color: #808000;">Dictionary</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><EventCoupling>> eventSources, </span><span style="color: #003300;"> </span><span style="color: #808000;">Dictionary</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">, </span><span style="color: #808000;">List</span><span style="color: #000000;"><MethodCoupling>> eventTargets)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(</span><span style="color: #0000ff;">string </span><span style="color: #000000;">key </span><span style="color: #0000ff;">in </span><span style="color: #000000;">eventSources.Keys)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">if</span><span style="color: #000000;">(!eventTargets.ContainsKey(key))</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">continue</span><span style="color: #000000;">;</span> <span style="color: #000000;">}</span></span> <span style="font-family: Lucida Console;"> <span style="color: #808000;">List</span><span style="color: #000000;"><MethodCoupling> targets = eventTargets[key];</span> <span style="color: #808000;">List</span><span style="color: #000000;"><EventCoupling> sources = eventSources[key];</span></span> <span style="font-family: Lucida Console;"> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(EventCoupling source </span><span style="color: #0000ff;">in </span><span style="color: #000000;">sources)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">foreach</span><span style="color: #000000;">(MethodCoupling target </span><span style="color: #0000ff;">in </span><span style="color: #000000;">targets)</span> <span style="color: #000000;">{</span> <span style="color: #808000;">Delegate </span><span style="color: #000000;">d = </span><span style="color: #808000;">Delegate</span><span style="color: #000000;">.CreateDelegate(</span> <span style="color: #000000;">source.Event.EventHandlerType, </span><span style="color: #003300;"> </span></span><span style="font-family: Lucida Console;">target.Command, target.Method);</span> <span style="font-family: Lucida Console;"> source.Event.AddEventHandler(source.Command, d); } } } }</span> |
It’s as simple as that: we loop through each event (publishers) and see if there is a list of methods (subscribers) to handle it in the chain. If so, we add a delegate as a handler to the event. In my sample project, I created three simple command types to demonstrate; here’s the output when I run my program:
You can see, once the key is generated in the first command, the value is available in the downstream commands using the events. The nice thing is that we can add more steps to our logic without much extra work. This is particularly handy for something like implementing a chain of validation rules as it means that you don’t end up writing a big if if block. But even in general usage, this pattern is useful for breaking out a large method into smaller, more modular pieces in a much more extensible manner.
One neat thing is that it allows you to not only wire events downstream, but also upstream as well. This means that if an element in your chain triggers an event, code in a previous even is executed if there is a handler wired for it.
In a more complete implementation, you may consider using Spring.NET or Unity or simply .NET configuration to statically identify the elements of the chain (instead of the basic reflection I’ve used). You may also consider more error handling logic š and passing an instance of a context through each element in the chain.
The full sample project is available here: ChainOfCommandSample.zip (11.21 KB)
What you describe seems very close to the Pipe & Filters pattern. How do you feel the two patterns compare?
-mike
Mike,
As far as I can tell, Pipe and Filters is a higher level abstraction (in most contexts, it’s used in discussion of message handling) than Chain of {Something}. I think the best way to describe the relationship is that Chain of {Something} can be used to _implement_ Pipe and Filters.
But the gist of the idea is the same: break up logic into small, more modular, more pluggable units.