Delegates Vs Command Pattern

Delegates: one of the few unique aspects of .NET. How useful are they? Here’s a delegate declaration. The syntax can take some getting used to.

In order to use the Operation delegate we’ll need some methods that match the double (double, double) form.

1 private delegate double Operation(double a, double b);
 1 public static double Add(double a, double b)
 2 {
 3     return a + b;
 4 }
 5 
 6 public static double Subtract(double a, double b)
 7 {
 8     return a - b;
 9 }
10 
11 public static double Multiply(double a, double b)
12 {
13     return a * b;
14 }
15 
16 public static double Divide(double a, double b)
17 {
18     return a / b;
19 }

There’s nothing special about that. Now to create an instance of the Operation delegate.

1 Operation math = new Operation(Add)

Again the syntax can throw you off a bit. This line instantiates an instance of Operation with the Add method and stores it in a variable named math. To use math you invoke it as though you were calling a method.

1 double result = math(1, 2);
2 Console.WriteLine("result: {0}", result);
3 >> 3

Invoking math, with parameters 1 and 2, actually called Add with the same parameters, hence the result of 3. The oposite behavior can be achieved by using the Subtract method instead of Add.

1 Operation math = new Operation(Subtract);
2 double result = math(1, 2);
3 Console.WriteLine("result: {0}", result);
4 >> -1

Math just delegated the call with parameters 1 and 2 to Subtract and so the result was -1. So far this isn’t very useful.

We can wrap methods up in delegates and call methods through the delegate but that’s just a lot of extra work. The power of Delegates comes into play when you don’t know which method to use.

Assume this code was used in a bank system. A frequent action of a bank system is to adjust the balance of an account.

1 private double balance = 0;
2 public void AdjustBalanceBy(double adjustment, Operation operation)
3 {
4     double newBalance = operation(balance, adjustment);
5     LogAdjustment(balance, newBalance);
6     balance = newBalance;
7 }

Notice that AdjustBalanceBy takes an Operation Which means it could be Add, Subtract, Multiply, or Divide to adjust the balance.

There might be operations we haven’t considered yet like applying interest. AdjustBalanceBy could take care of that for us as long as we give it a delegate that calls ApplyInterest(double, double).

The code in AdjustBalanceBy would never have to change and that’s exactly how the Open/Closed Principle says it should be. How would this be done without delegates? The Command Pattern would work great!

 1 public interface Operation
 2 {
 3     double Run(double a, double b);
 4 }
 5 
 6 public class Add : Operation
 7 {
 8     public double Run(double a, double b)
 9     {
10         return a + b;
11     }
12 }
13 
14 public class Subtract: Operation
15 {
16     public double Run(double a, double b)
17     {
18         return a - b;
19     }
20 }
21 ...
22 public void AdjustBalanceBy(double adjustment, Operation operation)
23 {
24     double newBalance = operation.Run(balance, adjustment);
25     LogAdjustment(balance, newBalance);
26     balance = newBalance;
27 }

There’s a bit more code without delegates but we’re saved from the wacky syntax. Considering the extra language complexity of delegates, I feel the Command pattern has the upper hand here. Point for Command Pattern.!meta Delegates 0 - Command Pattern 1.

What about multicasting?

Delegates have this feature called multicasting that allows you to add multiple delegates together. Here’s an example:

1 Operator math = new Operator(Add);
2 math += new Operator(Subtract);
3 math += new Operator(Multiply);
4 math += new Operator(Divide);
5 math(1, 2);

When math is called at the bottom, all four operations are performed. In this case it’s not particularly useful but for something like a button, where, when clicked, multiple actions need to take place, multicasting is very convenient. But what happens to all the return values?

Each of the methods combined in the math delegate above returns a value but math can only return one value.

 1 Operation math = new Operation(add);
 2 double result = math(1, 2);
 3 Console.WriteLine("result 1: {0}", result);
 4 
 5 math += new Operation(subtract);
 6 result = math(1, 2);
 7 Console.WriteLine("result 2: {0}", result);
 8 
 9 math += new Operation(multiply);
10 result = math(1, 2);
11 Console.WriteLine("result 3: {0}", result);
12 
13 math += new Operation(divide);
14 result = math(1, 2);
15 Console.WriteLine("result 4: {0}", result);
16 
17 OUTPUT
18 >>result 1: 3
19 >>result 2: -1
20 >>result 3: 2
21 >>result 4: 0.5

Interesting. Multicasted delegates only return one value from the combined execution. This suggests that multicasting should only be used when you don’t really care what the return values are.

The Command Pattern alone can’t compete with multicasting but along with his good buddy Composite, they’ve got things under control.

 1 public class Composite : Operation
 2 {
 3     IList operations = new ArrayList();
 4 
 5     public double Run(double a, double b)
 6     {
 7         double result = 0;
 8         foreach(Operation o in operations)
 9             result = o.Run(a, b);
10 
11         return result;
12     }
13 
14     public void AddOperation(Operation o)
15     {
16         operations.Add(o);
17     }
18 }

This version of Composite mimics the delegate’s handling of the return values but it could easily average them, store them in a list, or do whatever else your funny bone fancies.

Composite gives much more control over combined execution and so I say it earns another point for Command Pattern. !meta Delegates 0 - Command Pattern 2

Events

Oh gosh. Get a load of this syntax.

1 button.Click += new System.EventHandler(SomeAction);

An intuitive interpretation: button.Click - Telling the button that it was clicked button.Click += - Adding something to the clicking of the button…Huh? new System.EventHandler(SomeAction) - SomeAction must be a method the fits the EventHandler method form.

An instance of EventHandler is created with SomeAction. After those logical steps a developer concludes that Click must be a public field (or property) of Button of EventHandler which is a delegate.

And the developer would be wrong! Click is actually an Event. The declaration looks something like this:

1  
2 public event System.EventHandler Click;

The whole Event construct is rather silly because, as far as I can tell, it could just as easily be replaced with a public field (or property). 1 point deduction from delegates for flagrant misuse of syntax.

Final Score Delegates: -1; Command Pattern: 2

Micah Martin, Co-founder and Software Craftsman

Micah Martin is co-founder of 8th Light and is known for his open source work such as FitNesse, Limelight, Joodo, and Speclj.