BlackWasp
Design Patterns
.NET 2.0+

Command Design Pattern

The command pattern is a design pattern that enables all of the information for a request to be contained within a single object. The command can then be invoked as required, often as part of a batch of queued commands with rollback capabilities.

What is the Command Pattern?

The command pattern is a Gang of Four design pattern. This is a behavioural pattern as it defines a manner for controlling communication between classes or entities. The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. Often a queue of commands will be created that can be executed in a batch.

The command object does not contain the functionality that is to be executed, only the information required to perform an action. The functionality is contained within receiver objects. This removes the direct link between the command definitions and the functionality, promoting loose coupling. Neither of these object types is responsible for determining the time of execution of the command. This is controlled using an invoker.

The command pattern is useful when supporting activities that require the execution of a series of commands. The command objects can be held in a queue and processed sequentially. If each command is stored on a stack after it is executed, and if the commands are reversible, this allows the implementation of a rollback or multi-level undo facility.

An example of the use of the command design pattern could be used when remote controlling a robot, such as those used in space programmes. In our example, the receiver would be the robot. The receiver class would include methods that allowed the robot to move a specific distance forwards or backwards and to rotate to the left or right. It may also include methods that allowed a soil sample to be taken or released. To control the robot, a sequence of commands would be added to a queue held in the invoker object. When the commands are to be executed, the invoker would process the queue and add the commands to an undo stack.

Implementing the Command Pattern

Command Design Pattern UML

The UML class diagram above shows an implementation of the command design pattern. The items in the diagram are described below:

  • Client. The class is a consumer of the classes of the command design pattern. It creates the command objects and links them to receivers.
  • Receiver. Receiver objects contain the methods that are executed when one or more commands are invoked. This allows the actual functionality to be held separately to the Command definitions.
  • CommandBase. This abstract class is the base class for all command objects. It defines a protected field that holds the Receiver that is linked to the command, which is usually set via a constructor. The class also defines an abstract method that is used by the Invoker to execute commands.
  • ConcreteCommand. Concrete command classes are subclasses of CommandBase. In addition to implementing the Execute method, they contain all of the information that is required to correctly perform the action using the linked Receiver object.
  • Invoker. The Invoker object initiates the execution of commands. The invoker could be controlled by the Client object, as in the example code below. However, the invoker may be disconnected from the client. For example, the client could create a queue of commands that are executed periodically by a timed event.

The following shows the basic code of the command design pattern implemented using C#. To simplify the example the code uses C# 3.0 automatically implemented property syntax to define properties. For earlier versions of the language you should use full property declarations with backing variables.

public class Client
{
    public void RunCommand()
    {
        Invoker invoker = new Invoker();
        Receiver receiver = new Receiver();
        ConcreteCommand command = new ConcreteCommand(receiver);
        command.Parameter = "Hello, world!";
        invoker.Command = command;
        invoker.ExecuteCommand();
    }
}


public class Receiver
{
    public void Action(string message)
    {
        Console.WriteLine("Action called with message, '{0}'.", message);
    }
}


public class Invoker
{
    public CommandBase Command { get; set; }

    public void ExecuteCommand()
    {
        Command.Execute();
    }
}


public abstract class CommandBase
{
    protected Receiver _receiver;

    public CommandBase(Receiver receiver)
    {
        _receiver = receiver;
    }

    public abstract void Execute();
}


public class ConcreteCommand : CommandBase
{
    public string Parameter { get; set; }

    public ConcreteCommand(Receiver receiver) : base(receiver) { }

    public override void Execute()
    {
        _receiver.Action(Parameter);
    }
}

Example Command

In the opening section of the article an example of the command design pattern was described. In the example the pattern was used to control the actions of a robot. This robot would be remotely controlled, as it would be on the surface of another planet.

In the example, the commands dictate the movement of the robot and the use of a scoop to sample the planet's surface. The receiver would be the robot itself and the invoker would be a timed system running within the robot's software. The client would be controlled by the users on Earth who could create a queue of commands. The robot would also include an undo function to reverse a number commands as required.

In this section of the article we will create a simplified version of the classes that could be used to control such a robot. The first class will be the abstract base class for robot commands. This is slightly different to CommandBase in the earlier code as it includes an Undo method as well as an Execute method.

public abstract class RobotCommand
{
    protected Robot _robot;

    public RobotCommand(Robot robot)
    {
        _robot = robot;
    }

    public abstract void Execute();

    public abstract void Undo();
}

We can now create the three commands that the robot will be able to perform. The first command will allow the robot to be moved forwards by a specified number of millimetres. If the value given is negative, the robot will move backwards. A similar command will allow the robot to be rotated a number of degrees to the left, or to the right when the value is negative. The third command moves the sample-gathering scoop upwards or downwards. In each command, the Execute and Undo methods are implemented. The Undo method is the reverse operation to Execute.

public class MoveCommand : RobotCommand
{
    public int ForwardDistance { get; set; }

    public MoveCommand(Robot robot) : base(robot) { }

    public override void Execute()
    {
        _robot.Move(ForwardDistance);
    }

    public override void Undo()
    {
        _robot.Move(-ForwardDistance);
    }
}


public class RotateCommand : RobotCommand
{
    public double LeftRotation { get; set; }

    public RotateCommand(Robot robot) : base(robot) { }

    public override void Execute()
    {
        _robot.RotateLeft(LeftRotation);
    }

    public override void Undo()
    {
        _robot.RotateLeft(-LeftRotation);
    }
}


public class ScoopCommand : RobotCommand
{
    public bool ScoopUpwards { get; set; }

    public ScoopCommand(Robot robot) : base(robot) { }

    public override void Execute()
    {
        _robot.Scoop(ScoopUpwards);
    }

    public override void Undo()
    {
        _robot.Scoop(!ScoopUpwards);
    }
}

With the commands in place we can create the functionality that supports them. This will be held within a single receiver class that named "Robot". Rather than actually track the progress of a simulated robot, each method outputs some text to the console to explain the action that would have occurred in the real system.

public class Robot
{
    public void Move(int forwardDistance)
    {
        if (forwardDistance > 0)
        {
            Console.WriteLine("Robot moved forwards {0}mm.", forwardDistance);
        }
        else
        {
            Console.WriteLine("Robot moved backwards {0}mm.", -forwardDistance);
        }
    }

    public void RotateLeft(double leftRotation)
    {
        if (leftRotation > 0)
        {
            Console.WriteLine("Robot rotated left {0} degrees.", leftRotation);
        }
        else
        {
            Console.WriteLine("Robot rotated right {0} degrees.", -leftRotation);
        }
    }

    public void Scoop(bool upwards)
    {
        if (upwards)
        {
            Console.WriteLine("Robot gathered soil in scoop.");
        }
        else
        {
            Console.WriteLine("Robot released scoop contents.");
        }
    }
}

To complete the key classes of the pattern we must now code the invoker. This will be an enhanced version of that in the template code for the pattern, as it will contain a queue of commands rather than a single reference. In addition, a stack of commands will be used to keep a record of the robot's activities. This stack can then be used to undo commands that were executed in error. The code for the invoker is as follows:

public class RobotController
{
    public Queue<RobotCommand> Commands;
    private Stack<RobotCommand> _undoStack;

    public RobotController()
    {
        Commands = new Queue<RobotCommand>();
        _undoStack = new Stack<RobotCommand>();
    }

    public void ExecuteCommands()
    {
        Console.WriteLine("EXECUTING COMMANDS.");

        while (Commands.Count > 0)
        {
            RobotCommand command = Commands.Dequeue();
            command.Execute();
            _undoStack.Push(command);
        }
    }

    public void UndoCommands(int numUndos)
    {
        Console.WriteLine("REVERSING {0} COMMAND(S).", numUndos);

        while (numUndos > 0 && _undoStack.Count > 0)
        {
            RobotCommand command = _undoStack.Pop();
            command.Undo();
            numUndos--;
        }
    }
}

Testing the Command

To test the robot commands, we can use the Main method of a console application as the Client class of the design pattern. Add the following code to the Main method. This creates a queue of three commands and executes them. It then uses to undo function to reverse all three commands, returning the robot to its initial position and state. Execute the code to see the results.

Robot robot = new Robot();
RobotController controller = new RobotController();

MoveCommand move = new MoveCommand(robot);
move.ForwardDistance = 1000;
controller.Commands.Enqueue(move);

RotateCommand rotate = new RotateCommand(robot);
rotate.LeftRotation = 45;
controller.Commands.Enqueue(rotate);

ScoopCommand scoop = new ScoopCommand(robot);
scoop.ScoopUpwards = true;
controller.Commands.Enqueue(scoop);

controller.ExecuteCommands();
controller.UndoCommands(3);

/* OUTPUT

EXECUTING COMMANDS.
Robot moved forwards 1000mm.
Robot rotated left 45 degrees.
Robot gathered soil in scoop.
REVERSING 3 COMMAND(S).
Robot released scoop contents.
Robot rotated right 45 degrees.
Robot moved backwards 1000mm.

*/
Link to this Page9 August 2009
TwitterTwitter RSS Feed RSS