Command Pattern
Command Pattern
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Intent
The Command pattern converts a request into a standalone object that contains all information about the request. The object can be stored, queued, scheduled, logged, and replayed — and because it carries the receiver and its parameters, it can be undone. The Invoker that triggers commands needs to know only one thing about them: they have an execute() method.
When NOT to Use
- A simple direct method call suffices — wrapping every action in a Command object adds class overhead without benefit
- No requirement for undo/redo, queuing, logging, or remote execution — these are the scenarios that justify the pattern
- The command hierarchy grows large without reuse — if each command is used exactly once and never queued or undone, the abstraction is premature
When to Use
- The application needs undo/redo history — each Command can store pre-execution state or an inverse operation
- Actions must be queued, scheduled for deferred execution, or transmitted over a network
- A callback (closure) does not carry enough context — Command objects bind receiver, method, and parameters together explicitly
- Multiple invokers need to trigger the same operation on different receivers without knowing receiver specifics
How It Works
Participants:
- Command — interface declaring
execute()(and optionallyundo()) - ConcreteCommand — binds a specific Receiver instance and a set of parameters;
execute()calls the appropriate Receiver method - Receiver — the object that performs the actual work (knows how to carry out the operation)
- Invoker — asks the Command to carry out a request; may hold a history array for undo/replay
- Client — creates the ConcreteCommand and sets its Receiver; hands the command to the Invoker
The Invoker is entirely decoupled from the Receiver — it knows only that commands have execute(). The ConcreteCommand bridges Invoker and Receiver.
Class Diagram
classDiagram
class Invoker {
-history : Command[]
+executeCommand(cmd : Command)
+undo()
}
class Command {
<<interface>>
+execute()*
+undo()*
}
class ConcreteCommandA {
-receiver : Receiver
-prevState
+execute()
+undo()
}
class ConcreteCommandB {
-receiver : Receiver
-prevState
+execute()
+undo()
}
class Receiver {
+actionA()
+actionB()
}
Invoker o-- Command : stores and invokes
Command <|.. ConcreteCommandA
Command <|.. ConcreteCommandB
ConcreteCommandA --> Receiver : calls
ConcreteCommandB --> Receiver : calls
note for Invoker "Tracks command history\nfor undo/redo support"
TypeScript Example
// Command — TypeScript
// Source: GoF Design Patterns, p.233
interface Command { execute(): void; }
class Light {
on() { console.log('Light on'); }
off() { console.log('Light off'); }
}
class LightOnCommand implements Command {
constructor(private light: Light) {}
execute() { this.light.on(); }
}
class Invoker {
private history: Command[] = [];
run(cmd: Command) {
cmd.execute();
this.history.push(cmd); // enables undo / replay
}
}
const invoker = new Invoker();
invoker.run(new LightOnCommand(new Light()));Java Example
// Command — Java
// Source: GoF Design Patterns, p.233
interface Command { void execute(); }
class Light {
public void on() { System.out.println("Light on"); }
public void off() { System.out.println("Light off"); }
}
class LightOnCommand implements Command {
private final Light light;
LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
}
class Invoker {
private final java.util.List<Command> history = new java.util.ArrayList<>();
public void run(Command cmd) {
cmd.execute();
history.add(cmd); // enables undo / replay
}
}Lineage Forward
Command → CQRS lineage:
The Command pattern is the upstream ancestor of the CQRS-Pattern (created Phase 12) command-dispatch model. In CQRS, every write operation is a Command object routed through a CommandBus to a handler — the Invoker/ConcreteCommand/Receiver triad maps directly to CommandBus/CommandHandler/Aggregate. The lineage continues: Command → CQRS → Orchestration-Saga-Pattern (Phase 13), where the Saga orchestrator issues Commands to coordinate distributed transactions.
Related Concepts
| Pattern | Relationship |
|---|---|
| Strategy-Pattern | Both encapsulate behaviour, but Command encapsulates a specific request with receiver state; Strategy encapsulates an algorithm without binding to a receiver |
| Memento-Pattern | Command + Memento = undo/redo system — Command triggers the action, Memento snapshots state for reversal |
| Chain-of-Responsibility-Pattern | CoR dispatches a request along a handler chain; Command encapsulates that request as a first-class object |
Sources
- Gamma, Helm, Johnson, Vlissides — Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, p.233
Backlinks
Notes that link here: GoF-Patterns-MOC