Sep 2, 2008

A Generic Command Pattern in .NET 3.5

The command pattern can be a powerful thing to use and yet it can be a right royal pain in the ar... let's just say it's annoying to implement it at time.  Why? Because each individual command needs to be represented as an object and in a system that supports many commands you end up with a class explosion.

For those of you who need a refresher on the command pattern it is stated as follows:

The command pattern encapsulates a request as an object, thereby letting you parameterise other objects with different requests, queue or log requests, and support undoable operations.

Yeah, great - OK so in plain English that means you create classes to represent commands and those command classes simply make calls to other objects when you execute them.  It's a fairly simple pattern.

So let's take as an example the command pattern implementation from the awesome Head First Design Patterns book and implement it in .NET instead of Java.

First we declare an interface for our command objects:

    public interface ICommand
{
void Execute();
}

Then we create a command to turn a light on:

    public class LightOnCommand : ICommand
{
private Light light;

public LightOnCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.On();
}
}

And finally we create a simple remote control class:

    public class SimpleRemoteControl
{
private ICommand slot;

public void SetCommand(ICommand command)
{
slot = command;
}

public void ButtonWasPressed()
{
slot.Execute();
}
}

So now if we wanted to use this in our code we could have a test like the following:

[TestMethod]
public void BasicExecuteTest()
{
SimpleRemoteControl remote = new SimpleRemoteControl();
Light light = new Light();
LightOnCommand lightOn = new LightOnCommand(light);
remote.SetCommand(lightOn);
remote.ButtonWasPressed();
Assert.IsTrue(light.IsOn);
}

Easy enough.  But now, let's say we want to add a command to turn our light off.  We would have to implement a new LightOffCommand class.  If we were using a TV remote we would then need commands for each of the channels, the volume buttons, a channel up/down button, an input selector, etc.  As you can imagine once you start creating a class per command you can easily end up in with hundreds of classes all of which look pretty much the same.


This is where generics and lambda expressions in .NET 3.5 can help us.


Let's take our ICommand interface and implement it with a generic class:

public class Command<T> : ICommand
{
private T target;
private Action<T> command;

public Command(T target, Action<T> command)
{
this.target = target;
this.command = command;
}

public void Execute()
{
command(target);
}
}

We now have a single class that is able to represent a whole range of commands without getting us into the class explosion situation we had previously.


The Action<T> command is a variable that will hold a lambda expression that doesn't return a value.  If we wanted a value returned we would need to use Func<T, TResult> instead.


When we want to create a command we now pass the object we want to take action on, as well as a command to execute. So now we can refactor our test and change it as follows:

[TestMethod]
public void BasicExecuteTest()
{
SimpleRemoteControl remote = new SimpleRemoteControl();
Light light = new Light();
var lightOn = new Command<Light>(light, l => l.On());
remote.SetCommand(lightOn);
remote.ButtonWasPressed();
Assert.IsTrue(light.IsOn);
}

So here we see that the LightOnCommand has been replaced with the new generic command Command<Light> command and that we are passing the object to target with our command as well as a lambda expression for the command itself.


What this means is that we can now declare commands as follows without needing to create individual classes for each command:

var lightOff = new Command<Light>(light, l => l.Off());
var strobeLight = new Command<Light>(light, l =>
{
l.On();
l.Off();
l.On();
l.Off();
l.On();
});

So much nicer!


We now have an implementation of the command pattern that is not only powerful, but much easier to code and maintain as well.


Of course, if there's a lot of command reuse in your application this implementation of the command pattern might not be for you as it could easily lead to cut & paste development, though with judicious use of an IoC container you should be able to overcome that particular issue.

5 comments:

  1. Hi Richard,

    Nice article :-)
    You could perhaps take it further... Using Action and closures you you wouldn't need the Command class, although you would still be using the command pattern. Eg,

    var l = new Light();
    var strobeLightCommand = () =>
    {
    l.On();
    l.Off();
    l.On();
    l.Off();
    l.On();
    };
    strobeLightCommand();

    Java programmers eat your hearts out :-) I suspect the command pattern using classes was invented for languages where functions were not first class objects, and could not be passed around.

    Cheers,
    James

    ReplyDelete
  2. Very Nice!

    Can you leverage off this and implement Undo/Redo as well?

    ReplyDelete
  3. Hi Guys,

    Could you please help me to implement this interface -

    interface IRobot {
    //Loads a new book on the robot. Takes number of pages in the book as //argument. Valid only when the robot is empty.
    void loadBook(int);
    //Eject existing book from the robot. Invalid when the robot is empty.
    void ejectBook();
    //Move to next page. Invalid when the robot is empty.
    void nextPage();
    //Move to previous page. Invalid when the robot is empty.
    void previousPage();
    //Goes to first page of the book. Invalid when the robot is empty.
    void goToBegin();
    //Goes to last page of the book. Invalid when the robot is empty.
    void goToEnd();
    }

    Thanks
    Amol

    ReplyDelete
  4. I enjoyed the article! simple and clean

    @James Crisp
    I think using closure does not replace using Command Pattern
    in your example the invoker is not decoupled from receiver! Also, it does not have enough flexibility. for example if you need some derived command classes (e.g. CompositeCommand, RoutedCommand) having a command class it is better way in terms of encapsulation and OOP.

    ReplyDelete
  5. heloo in the example of light ,how i can off all the lights with same button using command pattern

    ReplyDelete