Command
Wrap a request - receiver, method, arguments and all - in its own object, so it can be passed around, queued, logged, and undone.
The problem
You are building a text editor and you need a toolbar full of buttons. You have a nice
Button class. The obvious move is a subclass per button, each with its click behavior
baked in.
That gets ugly fast. You end up with a swarm of subclasses, each of which breaks whenever
someone edits the base Button - your GUI code is now hostage to your business logic.
Worse, some operations have several entry points. A user can copy from the toolbar, from
the context menu, or with Ctrl+C. Three triggers, one behavior, and no shared home for it.
Either you duplicate the operation in every trigger class, or you make menus depend on buttons - which is somehow the worse of two bad options.
The solution
Extract the request itself. Everything about it - the object being called, the method name, the argument list - moves into a command class with a single trigger method. Now the GUI object holds a command and fires it, without knowing which business object will receive it or what will happen next.
Make all commands implement the same interface, with an execute method that takes no
parameters. The parameters do not vanish; they become fields, set when the command is
constructed. That is what lets one Button class hold any command at all, and lets you
swap a sender's behavior at runtime by swapping its command object.
Once a request is an object, three things come free: it can be stored (undo history), queued (deferred execution), and serialized (send it over the network, run it after a restart).
- 1The button was handed a command object at setup time. Clicking it triggers that object - the button has no idea what cutting even is.
- 2One funnel for every command. The sender calls the interface method and waits for a yes-or-no answer about state changes.
- 3The command snapshots the editor text before touching anything. Undo is only possible because this happens first.
- 4Now the receiver does the actual work. The command is a courier, not a text editor.
- 5execute() returned true, so the command joins the history stack, backup and all. CopyCommand returns false and is skipped.
- 6Ctrl+Z later: the app grabs the most recent command without knowing or caring what class it is.
- 7The command restores what it saved. Every command knows how to reverse itself, so the app never needs a giant undo switch.
Structure
Five roles: the sender (or invoker) holds a command and triggers it; the command interface declares the trigger; concrete commands carry the arguments and forward the call; the receiver does the real work; and the client creates commands and hands them to senders. Note that the sender never builds its own commands - it gets them pre-configured.
Code
Same example three ways: an editor with copy, cut, paste, and a working undo stack.
When to use it
- You want to parameterize objects with operations - a configurable context menu, a keybinding table, a plugin that contributes actions.
- You need to queue, schedule, log, or remotely execute operations. A command is data, and data travels.
- You need undo and redo. The history is a stack of executed commands plus the state each one saved.
Pitfalls
- A whole new layer. You have inserted a class between every sender and receiver. For an app with four buttons that never change, this is ceremony, not architecture.
- Backups get expensive. Snapshotting state before every mutation eats memory. The alternative - having each command implement its own inverse operation - is cheaper but sometimes impossible to write correctly.
- Private state resists snapshotting. If the receiver hides the state you need to back up, reach for Memento rather than punching holes in encapsulation.
- Commands that do the work themselves. Merging command and receiver is a legitimate shortcut for trivial operations, but do it habitually and the business logic ends up scattered across your action classes.
Don't confuse it with
- Strategy. Both hand an object some behavior, and the class diagrams rhyme. Strategy describes different ways of doing the same thing, swapped inside one context. Command converts a single operation into an object precisely so you can defer it, queue it, record it, or reverse it. Ask what varies: the algorithm, or the timing and ownership.
- Chain of Responsibility. Command sets up a one-way link between one sender and one receiver. CoR passes a request down a line of candidates until one accepts. They stack nicely: chain handlers can be commands, and the request travelling the chain can be one.
- Memento. Frequently a pair. The command performs the operation; the memento captures the receiver's state just before it, without exposing that state to anyone.
- Visitor. Think of it as Command with ambitions - one object executing operations across many unrelated classes.
Check yourself
Why does the command interface usually declare execute() with no parameters?