Command Design Pattern
Definition:
Encapsulate a request as an object, thereby letting users parameterize clients with different requests, queue or log requests, and support undoable operations.
Breakdown:
You are not encapsulating the object that sends the request, or the object that receives the request, but encapsulate the actual request as an object with state.
Of course, some commands can be stateless chunks of pure behavior (no data members).
The command pattern also makes undoable/redoable operations a piece of cake (they're considerably harder to implement without it). Derived Commands can leverage CRTP to be statically bound.
Note that the code executing the commands is responsible for freeing their memory.
Design
- define a base abstract class
Command
that represents a triggerable command for the program - create subclasses of
Command
, each representing a different concrete Command to be executed and override the interface method eg.void execute()
(and optionally other operations eg.undo()/redo()
) - create a handler class
CommandHandler
to handle the commands supplied by the incoming requests. You could use a switch with an enum such asCommandId
to differentiate between the commands. - to support undo operations we store at the base command class the state that is being changed, ie all the state affected by the command and when
undo()
is requested we restore the oldstate. Likewise forredo()
. - to support multiple levels of undo instead of remembering the last command, we keep a
stack<CommandType> commands;
instead, and we point to the current one. When the user executes a command we push it to the stack. When the user undos we pop from the stack. When the user redos we first check if there is something to redo in the stack and proceed.
In my example I've used a slightly more complex version to create concrete Command
classes. Instead of using the classic inheritance with virtual functions and making the base Command
an interface (pure virtual) I resorted to the Curiously Recurring Template Pattern (aka Static Polymorphism) using templates. This is in general less flexible, more complicated but more performant. But more than that I wanted to illustrate a practical use for CRTP. To familiarize yourself with CRTP check this tutorial.
I used Windows and Visual Studio to build the project.
Github
Github repository link.