Card 01/ 09
Command Pattern: Turning a Request Into an Object
Once a request is an object, it can wait in a queue, be logged, or be undone.
The Command pattern wraps a request in an object with one method to carry it out, usually called execute. The code that triggers the request holds that object instead of calling the code that does the work, so the request can be stored, queued, logged, sent elsewhere, or reversed. This card covers the problem that calls for it, the intent, and when it fits.
The problem is a trigger tied to the code it runs. A toolbar button in a text editor calls editor.bold() directly. The button cannot be reused for another action, the call leaves no record, and once it has happened there is nothing to undo, because the request never existed as anything but a call.
Without the patternthe button knows the editor
class BoldButton:
def click(self):
self.editor.bold()One button class per action, and the call is gone once it has run.
With the patternthe button knows a command
class Button:
def __init__(self, command):
self.command = command
def click(self):
self.command.execute()
history.append(self.command)One button class for every action, and each press leaves an object in the history.
The Gang of Four state the intent as: encapsulate a request as an object, thereby letting you parameterise clients with different requests, queue or log requests, and support undoable operations.
An order ticket in a restaurant is a familiar picture. The waiter writes the order once, it waits on a rail until a cook is free, and it says exactly what to make without the waiter knowing how. The picture breaks on reversal: a meal cannot be uncooked, while a command that remembers what it changed can undo itself.
Command is one of eleven behavioural patterns, the family concerned with which object does which part of the work, and how objects communicate.
| Pattern | What it does |
|---|---|
| Chain of Responsibility | Passes a request along a chain of handlers until one handles it. |
| Command (this topic) | Turns a request into an object that can be stored, queued or undone. |
| Interpreter | Represents a small language's grammar as classes and evaluates its sentences. |
| Iterator | Visits the elements of a collection without exposing how it is stored. |
| Mediator | Routes the communication between objects through one central object. |
| Memento | Captures an object's state so it can be restored later. |
| Observer | Notifies many objects when one object changes. |
| State | Changes an object's behaviour when its internal state changes. |
| Strategy | Swaps one algorithm for another behind a common interface. |
| Template Method | Fixes an algorithm's steps in a base class and lets subclasses fill some in. |
| Visitor | Adds operations to a class hierarchy without changing its classes. |
Use it when
- An action must be undone, redone, or replayed.
- Requests must wait in a queue, run on another thread, or run at a scheduled time.
- The thing that triggers an action, such as a button or a menu item, should not know what the action does.
Avoid it when
- The action runs once, at once, and is never stored, so a direct call is clearer.
- Every command would be a class around a single call with no undo and no queue.
- The state an undo needs is the whole document, which is a snapshot's job rather than a command's.
← → move through sections and cards