Delegates Vs Command Pattern

Delegates Vs Command Pattern

Micah Martin
Micah Martin

September 07, 2006

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.

1private delegate double Operation(double a, double b);
 1public static double Add(double a, double b)
 3 return a + b;
 6public static double Subtract(double a, double b)
 8 return a - b;
11public static double Multiply(double a, double b)
13 return a * b;
16public static double Divide(double a, double b)
18 return a / b;

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

1Operation 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.

1double result = math(1, 2);
2Console.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.

1Operation math = new Operation(Subtract);
2double result = math(1, 2);
3Console.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.

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

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!

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

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:

1Operator math = new Operator(Add);
2math += new Operator(Subtract);
3math += new Operator(Multiply);
4math += new Operator(Divide);
5math(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.

 1Operation math = new Operation(add);
 2double result = math(1, 2);
 3Console.WriteLine("result 1: {0}", result);
 5math += new Operation(subtract);
 6result = math(1, 2);
 7Console.WriteLine("result 2: {0}", result);
 9math += new Operation(multiply);
10result = math(1, 2);
11Console.WriteLine("result 3: {0}", result);
13math += new Operation(divide);
14result = math(1, 2);
15Console.WriteLine("result 4: {0}", result);
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.

 1public class Composite : Operation
 3 IList operations = new ArrayList();
 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);
11 return result;
12 }
14 public void AddOperation(Operation o)
15 {
16 operations.Add(o);
17 }

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


Oh gosh. Get a load of this syntax.

1button.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:

2public 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