In software engineering, Behavioural Design Patterns deal with the assignment of responsibilities between objects which in turn make the interaction between the objects easy & loosely coupled. In this article of the Behavioural Design Patterns, we’re going to take a look at Command Design Pattern in Modern C++ which encapsulate all the details related to operation into a separate object. Command Design Pattern is widely used in sophisticated software. In fact, you might be using it every day without even knowing that. For example, whenever you press Ctrl + Z
(i.e. undo/redo), you are likely firing the object arrangements organised as a Command Pattern.
By the way, If you haven’t check out my other articles on Behavioural Design Patterns, then here is the list:
- Chain of responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
The code snippets you see throughout this series of articles are simplified not sophisticated. So you often see me not using keywords like override
, final
, public
(while inheritance) just to make code compact & consumable(most of the time) in single standard screen size. I also prefer struct
instead of class
just to save line by not writing “public:
” sometimes and also miss virtual destructor, constructor, copy constructor, prefix std::
, deleting dynamic memory, intentionally. I also consider myself a pragmatic person who wants to convey an idea in the simplest way possible rather than the standard way or using Jargons.
Note:
- If you stumbled here directly, then I would suggest you go through What is design pattern? first, even if it is trivial. I believe it will encourage you to explore more on this topic.
- All of this code you encounter in this series of articles are compiled using C++20(though I have used Modern C++ features up to C++17 in most cases). So if you don’t have access to the latest compiler you can use https://wandbox.org/ which has preinstalled boost library as well.
Intent
To decouples the sender & receiver by creating a separate object for a set of operations.
- The Command Design Pattern is quite simply an object to represent instructions or set of instructions which also facilitates the support of undo-able operations & query/request customization.
- There is one thing that I want to mention which isn’t directly related to the subject of the Command Design Pattern. But still, let me clarify that Command & Query are two different aspects.
- Command: Asking for action or change e.g. renaming a file.
- Query: Asking for information(doesn’t cause any mutation) e.g. list all the file in the current directory.
- So, this idea of command query separation is something that used in a lot of things like distributed databases for example. Where you basically split your system into separate components and separate means of sending commands. I just wants to make this point so that you don’t get confuse later on. Because GoF mentions command & query as the same thing.
Trivial Command Design Pattern Example in C++
|
|
- I know its silly example with overloaded call operator(i.e functor), but consider it a good start especially for
macroCommand
.
Practical Approach to Command Design Pattern
- Following is a practical example of the Command Design Pattern with a very familiar scenario of bank account:
|
|
- As you can see
BankAccount
class with minimalistic implementation having some amount of starting balance. We do also havedeposit()
&withdraw()
methods but rather than using those methods directly we will create a separate entityBankAccountCommand
backed by abstract classCommand
. - And in the
main()
, we have carried out the money transfer of200
from one bank account to another. Each command has reference to particularBankAccount
so it knows on which account to operate on. - So this idea of keeping every single command that invokes on a bank account gives us interesting possibilities.
- One of those possibilities is to implement undo(as you find in Microsoft office applications by pressing
Ctrl + Z
) functionality so when you want to roll back one of these commands you can actually get it done easily. - Another possibility is you can create code more abstract in a way which works like a recorded macro. Think about the implementation of macros in a Microsoft Office application for example. That is a sequence of commands that gets recorded one after another. And you can sort of playback all the commands one after another. And you can also undo them all in reverse order with a single invocation.
- One of those possibilities is to implement undo(as you find in Microsoft office applications by pressing
- Following is an improved example incorporating above two possibilities with Composite Design Pattern:
|
|
Benefits of Command Design Pattern
- Command Design Pattern decouples operand & operation. Thus facilitates extensions to add a new command is easy and without changing the existing code.
- By queueing commands, you can also define a rollback functionality in the system as we did above.
- It also allows us to create a macro with a bunch of commands can fire together in a single invocation.
- As the Command Design Pattern has a separate structure to store a set of operations, we have the leverage to schedule it.
Summary by FAQs
What is the important aspect of the Command Design Pattern?
1. Interface separation: the invoker is isolated from the receiver.
2. Time separation: stores a ready-to-go set of instructions that can be scheduled.
What is the reason behind using the Command Design Pattern?
- Decouple the sender & receiver of the command
- Implement the callback mechanism
- Implement undo and redo functionality
- Maintain a history of commands
Difference between Command & Memento Design Pattern?
Command Design Pattern represents request token
Memento Design Pattern represents the internal state of an object at a particular time
Polymorphism is important to Command, but not to Memento.