Author image

Command Design Pattern


Difficulty:
1/5


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 operations a piece of cake (they're considerably harder to implement wihout it). Derived Commands can leverage CRTP to be statically bound. To familiarize yourself with CRTP check this tutorial.

Note that the code executing the commands is responsible for freeing their memory.

Design

  • define a base class or interface (abstract class) Command that represents a triggerable command for the program
  • create subclasses of Command, each representing a different Command to be executed and override the interface method eg. void execute() (and optionally the undo operation void undo())
  • create a handler class which stores a pointer for each type of possible concrete Command subclass
  • use a executeCommand() in the CommandHandler class to handle and dispatch the appropriate commands depending on the incoming requests
  • you can use a switch aka an enum such as CommandId to differentiate between the commands in the CommandHandler::executeCommand()
  • 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 for redo.
  • to support multiple levels of undo instead of remembering the last command, we keep a stack<CommandType> commands; (or queue) 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 using the Curiously Recurring Template Pattern (aka Static Polymorphism) with templates. This is in general less flexible, more complicated but more performant.

I used Windows 8.1 x86_64, Visual Studio 2017, C++17 to build the project.

Github

Github repository link.


0 likes