Command Pattern
Concept Definition
Command turns a request into an object. Instead of calling an action immediately, you store an object that knows how to execute that action later. The caller can queue, log, retry, or undo commands using one common interface.
Think of a remote control button. The button does not know the details of a fan or light; it only triggers the command assigned to it.
Why It Matters
Many programs need to treat actions uniformly. A menu item, toolbar button, keyboard shortcut, task queue, or transaction log may all need the same operation: execute(). Command separates the object that asks for work from the object that performs the work.
Command is also a bridge from basic polymorphism to real application design. It applies OOP to verbs, not only nouns.
Syntax Block
class Command {
public:
virtual ~Command() = default; // safe base cleanup
virtual void execute() = 0; // action contract
};
Explained Code
Example: Toolbar Commands
#include <iostream> // std::cout
#include <memory> // std::unique_ptr
#include <vector> // std::vector
class Command {
public:
virtual ~Command() = default; // safe polymorphic deletion
virtual void execute() = 0; // common action
};
class SaveCommand : public Command {
public:
void execute() override { std::cout << "Saved\n"; } // perform save action
};
class Toolbar {
private:
std::vector<std::unique_ptr<Command>> commands; // owns command objects
public:
void add(std::unique_ptr<Command> command) { // receive action object
commands.push_back(std::move(command)); // store for later
}
void runAll() {
for (auto& command : commands) { command->execute(); } // execute uniformly
}
};
Toolbar does not know what each button does. It only stores commands and calls execute().
Key Points / Rules
- Use Command when actions need to be stored, delayed, queued, logged, or undone.
- The invoker calls the command; the receiver performs the real work.
- A command object can hold the data needed to perform the action.
- Use
std::unique_ptr<Command>when a container owns commands polymorphically. - Add
undo()only when the command can truly reverse its effect.
Common Mistakes
- Making commands too large. A command should represent one clear action.
- Letting the invoker know concrete command types. That reintroduces coupling.
- Claiming undo is easy for every command. Some actions, such as sending an email, cannot be perfectly undone.
- Using Command for direct one-line calls. If nothing is stored or delayed, a function call may be simpler.
Quick Check
- What method does every command class implement?
- Why can
Toolbarrun different commands through the same loop?
Viva Answer
Command represents an action as an object. It is useful for queues, button actions, logging, retry systems, and undo/redo designs.