Command Design Pattern
The Command Pattern
The Gang of Four’s book gives the following definition of the command pattern:
“The Command pattern encapsulates a request as an object, letting you parameterize clients with different requests. It allows to queue or log requests, and to support undoable operations.”
The central point here is the phrase “encapsulate a request as an object”. The aim of the pattern is to create an object that represents a method call. To do that we need to encapsulate the object on which the method is called, the method itself, and the parameters passed to it, if any. We say that the method invocation is reified (from the latin res, meaning thing), it’s wrapped into an object, and as a first class object it can be treated as such, passed around, and executed at a different time, even by a different thread. In its simplest form, the Command interface defines a single method Execute(), taking no parameters and returning void. Here’s the structure of the pattern and its participants:
The method takes no parameters whatsoever because it’s the instance of the concrete command class implementing the Command interface that contains all that’s needed to call the method. It has the knowledge to perform the action and mantains a reference to an object of a receiver class and knows which method (or methods) to call, and the parameters to pass to each call, if any. Generally, the receiver and the parameters are binded upon instatiation of the concrete command. The receiver can be any class.
Of course a command is useless without something that can issue it, or invoke it. An invoker has references to one or more commands and it can issue them whenever it has to (whenever the client of the invoker asks for a command to be issued). References to command interfaces can be set at construction, or through setter methods, enabling an invoker to change (to be parameterized with, as the GoF definition says) different commands even at runtime. The invoker doesn’t know anything about the specific operation that will be performed, nor it has details on the specific object (the receiver of the command) that actuallt performs the action. It just uses the Command interface, delegating to the command’s Execute() method. So the invoker and the receiver of the action/command are decoupled.
As an example, let’s consider the case of a game in which a unit (the receiver) moves on a grid and we want to issue a command to move the unit into a specific position. The unit has a MoveTo() member function that sets its new position on the map (and prints its current position):
// Command.h // receiver class Unit { public: Unit() : m_x(0), m_y(0) {} void MoveTo(int x, int y); private: int m_x; // current position on the map grid int m_y; }; // Command.cpp #include <iostream> void Unit::MoveTo(int x, int y) { m_x = x; m_y = y; // print position std::cout << "unit in x: " << m_x << " y: " << m_y << std::endl; }
A class called InputHandler handles the input from the player, but we don’t want to hardcode the action that it performs into the class’ code. Instead we make InputHandler store a reference to a Command object, and provide InputHandler with a setter function that sets the current command:
// Command.h // invoker class InputHandler { public: InputHandler() : m_command(new NullCommand) {} // invoker's default command is the null command void SetCommand(Command *command) { m_command = command; } void DoCommand() { m_command->Execute(); } private: Command *m_command; };
All the DoCommand() function does calling the command interface’s method Execute(), thus delegating the action to the concrete command implementation. We define two concrete commands implementations: one is the null command, whose Execute() method does nothing. The InputHandler’s default command is the null command, that is, a command that performs no action (this is a common pattern called Null Object, that allows us to not check if the current set command is a nullptr). We then define the command to move the unit:
// Command.h // abstract command interface class Command { public: virtual ~Command() {} virtual void Execute() = 0; protected: Command() {} }; // concrete command class MoveUnitCommand : public Command { public: MoveUnitCommand(Unit *unit, int x, int y) : m_unit(unit), m_x(x), m_y(y) {} void Execute() override; private: Unit *m_unit; const int m_x; const int m_y; }; // null command (null object pattern) class NullCommand : public Command { public: void Execute() override {} };
In this case the action to be performed requires a couple of parameters (the x and y position of the grid where we want to move the unit). As we saw in the diagram, they’re passed into the constructor, along with the instance of the receiver, the unit to be moved in our example: it essential to understand that an instance of a concrete command class represents a specific method/function call, an action that we want to perform, so we need to parametrize it with the parameters needed for the specific invocation.
And that’s it, this is the essence of the command pattern. A simple test client shows how it works:
// main.cpp #include "Command.h" int main(int argc, char **argv) { Unit unit; Command *command1 = new MoveUnitCommand(&unit, 10, 20); Command *command2 = new MoveUnitCommand(&unit, 11, 20); Command *command3 = new MoveUnitCommand(&unit, 10, 22); Command *command4 = new MoveUnitCommand(&unit, 33, 4); Command *command5 = new MoveUnitCommand(&unit, 0, 5); InputHandler inputHandler; inputHandler.SetCommand(command1); inputHandler.DoCommand(); inputHandler.SetCommand(command2); inputHandler.DoCommand(); inputHandler.SetCommand(command3); inputHandler.DoCommand(); inputHandler.SetCommand(command4); inputHandler.DoCommand(); inputHandler.SetCommand(command5); inputHandler.DoCommand(); return 0; }
The output from the program is:
unit in x: 10 y: 20 unit in x: 11 y: 20 unit in x: 10 y: 22 unit in x: 33 y: 4 unit in x: 0 y: 5
So the Command pattern lets us decouple a command/method invocation from the code that invokes the command, and wraps the invocation into an object that can be passed around, and stored, or called at a later time. But it doesn’t stop here. Let’s see what else the pattern has to offer.
Undoable commands
One of the most interesting and useful applications of the command pattern is supporting commands that can be undone. We can definde unodable commands simply by adding an Undo() method to the command interface:
In some cases concrete commands need to hold some state in order to remember the previous state of the receiver and to restore it back when an undo is performed. The good news is how simple it is to implement a multiple level undo/redo functionality. Since method invocations are first class objects now, the invoker can keep track of the executed commands by storing them into a data structure (a list, an array or whaterver, here I used a simple array). Implementing undo is as simple as walking back into the data structure and call the Undo() function on a previously stored command object, while to redo an operation we simply go forward into the structure and re-execute the command. Let’s update our example to support undo/redo: as we saw, the Command interface has a new Undo() method:
// Command.h // command class Command { public: virtual ~Command() {} virtual void Execute() = 0; virtual void Undo() = 0; protected: Command() {} };
The MoveUnitCommand class now needs to store the previous position of the unit, for when we want to undo a move operation and move back the unit into the previous position on the map. The Unit class now has a couple of getter methods in order to retrieve its current position:
// Command.h // concrete command class MoveUnitCommand : public Command { public: MoveUnitCommand(Unit *unit, int x, int y) : m_unit(unit), m_x(x), m_y(y), m_prev_x(0), m_prev_y(0) {} void Execute() override; void Undo() override; private: Unit *m_unit; const int m_x; const int m_y; int m_prev_x; int m_prev_y; }; // receiver class Unit { public: Unit() : m_x(0), m_y(0) {} void Move(int x, int y); int GetX() const { return m_x; } int GetY() const { return m_y; } private: int m_x; int m_y; };
The Execute() method needs to store the current position of the unit, so the Undo() method can restore it when called:
// Command.cpp void MoveUnitCommand::Execute() { // save receiver's state m_prev_x = m_unit->GetX(); m_prev_y = m_unit->GetY(); // perform action on receiver m_unit->Move(m_x, m_y); } void MoveUnitCommand::Undo() { // restore receiver's state m_unit->Move(m_prev_x, m_prev_y); }
The InputHandler class, our Invoker has changed a little: now it stores all executed commands in a suitable data structure , so it keeps track of all the commands that it has issued so far:
// Command.h // invoker #define SIZE 100 class InputHandler { public: ~InputHandler(); InputHandler() : m_command(new NullCommand), m_count(0), m_index(0) {} void SetCommand(Command *command) { m_command = command; } void DoCommand(); void UndoCommand(); void RedoCommand(); private: Command *m_command; Command *m_executed_commands[SIZE]; // InputHandler owns the command objects (and must delete them when it's done with them) int m_count; // total executed commands int m_index; // index one past last current command };
When we want to execute a command, we set the command with the SetCommand() member function and call DoCommand(). The Invoker stores the command into the array along with all other executed commands. The count variable stores the total number of executed commands and the index variable indicates the current command into the array. If we want to undo the last operaton, we call UndoCommand(): this function moves back the current command index into the array and restore the previous state. Calling RedoCommand() moves the index forward and call Execute() on the current command object again. If we set a new command when the index is not after the last issued command, all the following commands are discarded:
// Command.cpp void InputHandler::DoCommand() { // execute command m_command->Execute(); // free discarded commands if (m_index != m_count) for (int i = m_index; i < m_count; i++) delete m_executed_commands[i]; // add COPY of command to command list m_executed_commands[m_index++] = m_command; m_count = m_index; } void InputHandler::UndoCommand() { if (m_index - 1 >= 0) m_executed_commands[--m_index]->Undo(); } void InputHandler::RedoCommand() { if (m_index < m_count) m_executed_commands[m_index++]->Execute(); }
(I also delete the discarded command objects, since I assume that they’re allocated dynamically by the client of the invoker.) Let’s test the new example:
// main.cpp #include "Command.h" int main(int argc, char **argv) { Unit unit; InputHandler in; Command *c = new MoveUnitCommand(&unit, 5, 6); in.SetCommand(c); in.DoCommand(); c = new MoveUnitCommand(&unit, 15, 0); in.SetCommand(c); in.DoCommand(); c = new MoveUnitCommand(&unit, 23, 11); in.SetCommand(c); in.DoCommand(); in.UndoCommand(); in.UndoCommand(); c = new MoveUnitCommand(&unit, 44, 2); in.SetCommand(c); in.DoCommand(); in.UndoCommand(); in.UndoCommand(); // reached head of array - initial state is 0,0 in.RedoCommand(); in.RedoCommand(); in.RedoCommand(); // reached tail of array - does nothing return 0; }
The output when the program is run is:
unit moves to x: 5 y: 6 unit moves to x: 15 y: 0 unit moves to x: 23 y: 11 unit moves to x: 15 y: 0 unit moves to x: 5 y: 6 unit moves to x: 44 y: 2 unit moves to x: 5 y: 6 unit moves to x: 0 y: 0 unit moves to x: 5 y: 6 unit moves to x: 44 y: 2
Using templates for simple commands
For commands that don’t require arguments and are undoable we can avoid creating a concrete command subclass for each command. We can instead use templates and create a class template whose template type parameter is the type of the receiver. The template mantains a reference to a receiver and stores a pointer to member function as the action to perform:
template <typename Receiver> class SimpleCommand : public Command { public: typedef void (Receiver::*Action)(); SimpleCommand(Receiver *receiver, Action action) : m_receiver(receiver), m_action(action) {} void Execute() override { (m_receiver->*m_action)(); } private: Receiver *m_receiver; Action m_action; };
the type alias Action represents a pointer to a member function of the Receiver class, taking no arguments and returning void. The Execute() method simply dereference the pointer and calls the member function.