Command Pattern
Learn to turn a request into a self-contained, queueable object with a standard execute() method, so an invoker like a UI button can trigger any action without knowing what it does.
Learning objectives
- Explain why hardcoding a receiver reference into an invoker like a button blocks reuse
- Separate a request into Command, Invoker, and Receiver roles
- Rewire an invoker to any new action at runtime by swapping its command
- Extend a Command interface to support undo and macro composition
- Identify Command's real-world equivalents in Runnable, Callable, and Swing's UndoManager
◆ Story
A waiter doesn't walk into the kitchen and cook a meal themselves. They write the order onto a slip and hand it to the kitchen. That slip is a self-contained, queueable request: it can sit in a stack of other orders, get picked up whenever the kitchen is ready, and even get handed back later with "cancel this" written on it. The waiter never needs to know how to cook anything — the slip just needs to know what was requested.
That's the core move behind this pattern: turn a request into a real object, instead of a raw method call that happens and disappears immediately.
A toolbar for a text editor makes this concrete. Buttons like bold and italic ideally come from a generic GUI framework someone else maintains — a Button class that needs to work for a text editor today, and potentially for a completely different application, a photo editor or a spreadsheet, tomorrow, without being rewritten for each one. Building the buttons the direct, hardcoded way first is what makes the eventual fix worth the extra indirection.
This problem sits one level up from Strategy's. Strategy swaps how a single, already-known action gets carried out. Command goes further: it turns the action itself — including which receiver it targets and when it fires — into an object that can be handed around, stored, queued, and replayed, entirely independent of who eventually triggers it.
The direct approach: each button holds a reference to the specific editor it controls, and calls the relevant method directly the moment it's clicked. A BoldButton holds a TextEditor field and calls editor.makeBold() from inside its click() method. An ItalicButton is a nearly identical class with one different hardcoded call.
Run it and it works — new BoldButton(editor).click() prints exactly what you'd expect. So is this fine? The real test is what happens the moment this Button class needs to ship as part of a reusable GUI framework, for applications that have never heard of TextEditor.
Every button here is a brand-new class, permanently welded to one editor and one action. A new toolbar action means a new button class, hardcoded the exact same way, forever. Worse, these buttons can never leave this specific application — a GUI framework's Button class needs to work for a photo editor, a spreadsheet, anything, not just TextEditor, and as written BoldButton is genuinely unusable anywhere TextEditor doesn't exist. And nothing lingers after a click: editor.makeBold() runs and is gone, with no object representing "what just happened" that anything could log, queue for later, or undo — a raw method call vanishes the instant it finishes executing.
The framework author writing Button genuinely cannot know, in advance, every action every future application will ever want a button to trigger. Hardcoding any specific one directly into the button class is backwards.
💻 Code example
class TextEditor { void makeBold() { System.out.println("Text has been bolded"); } void makeItalic() { System.out.println("Text has been italicized"); } } class BoldButton { private final TextEditor editor; // a direct, specific reference to the editor BoldButton(TextEditor editor) { this.editor = editor; } void click() { editor.makeBold(); // hardcoded — this button can only ever do exactly this } } // Every new toolbar action needs a near-identical new Button subclass, // permanently welded to TextEditor. This Button class could never ship // inside a reusable GUI framework used by other applications.
Reason through what a button should actually hold. A button shouldn't know what action it performs at all — only that, when clicked, something should happen. So "an action" needs to become a first-class object rather than a hardcoded method call, the same underlying move as pulling a varying algorithm out into its own interface. The button holds a reference to that action-object generically, and the code assembling the application — the part that actually knows about TextEditor — decides which action-object each button gets.
This is the Command pattern: wrap a request as a full object with a standard execute() method, so the button just calls execute() on whatever it's holding, with zero knowledge of which application or action is actually behind it.
Start with the contract: an interface with exactly one method, execute(), taking no parameters. Each old hardcoded action becomes its own class implementing that interface — but the reference to the editor moves from the button into the command. BoldCommand holds the TextEditor reference now, and its execute() body calls editor.makeBold(). That's its only job: knowing which editor call this specific command actually means.
Button is rebuilt to hold a Command field instead of a TextEditor — never anything application-specific. setCommand() lets whoever assembles the app decide what a button does; click() just calls command.execute(), generic delegation identical in shape to the strategy context's pay() method. This Button class no longer imports or references TextEditor anywhere at all. It could genuinely ship inside a separate GUI framework library, with the person building any application supplying whatever command makes sense for their own use case.
💻 Code example
interface Command { void execute(); // the ONE thing every command must be able to do } class BoldCommand implements Command { private final TextEditor editor; // the reference moved HERE from the button BoldCommand(TextEditor editor) { this.editor = editor; } public void execute() { editor.makeBold(); // this class's only job — knowing what this command means } } class ItalicCommand implements Command { private final TextEditor editor; ItalicCommand(TextEditor editor) { this.editor = editor; } public void execute() { editor.makeItalic(); } } class Button { private Command command; // holds ANY command, set from outside void setCommand(Command command) { // decided by whoever assembles the app this.command = command; } void click() { command.execute(); // generic delegation — Button never changes again } }
Wire a button to a command, click it, and confirm the output matches. Then prove the actual payoff: add a completely new toolbar action — changing text color — and check exactly what changes.
The entire diff required is one new method on the receiver, changeColor(), and one new command class, ChangeColorCommand, implementing Command the same way the other two do. Button is not touched at all. And there's a second thing worth noticing beyond "Button doesn't change": the exact same Button object, already constructed and already wired up, can be repointed at a completely different action at runtime just by calling setCommand() again with a new command. That's the concrete meaning of "decoupled" here — one button, any number of possible actions, decided from outside the button entirely.
| Step | What happens |
|---|---|
boldButton.setCommand(new BoldCommand(editor)) | button now wraps the bold action |
boldButton.click() | prints "Text has been bolded" |
boldButton.setCommand(new ChangeColorCommand(editor)) | same button object, repointed |
boldButton.click() | prints "Text color has been changed" — no new Button created |
Step back and notice what changed structurally between the hardcoded version and this one. Before, the number of button classes grew linearly with the number of actions — one class per action, forever. Now, the number of button classes is fixed at exactly one, and the number of command classes grows instead — which sounds like the same amount of code until you remember that Button itself, the class doing the actual UI work of rendering and detecting clicks, never needs to be touched, tested, or redeployed again for any future action anyone dreams up.
💻 Code example
class ChangeColorCommand implements Command { // one new class — Button is not touched private final TextEditor editor; ChangeColorCommand(TextEditor editor) { this.editor = editor; } public void execute() { editor.changeColor(); } // new receiver method } public class Main { public static void main(String[] args) { TextEditor editor = new TextEditor(); Button boldButton = new Button(); boldButton.setCommand(new BoldCommand(editor)); boldButton.click(); // Text has been bolded // the SAME Button object, repointed at a totally different action at runtime boldButton.setCommand(new ChangeColorCommand(editor)); boldButton.click(); // Text color has been changed } }
▲ Edge case — clicking a button with no command set
command defaults to null until setCommand() is called, so calling click() before that throws a NullPointerException. A real UI toolkit typically disables a button visually until a command is actually wired to it, rather than letting this surface as a crash at runtime.
▲ Edge case — undo needs a command to remember more than execute() alone provides
As built, execute() takes no parameters and returns nothing, so there's no way to reverse it. Supporting undo means each concrete command also implementing an undo() method, and often capturing whatever state is necessary to reverse itself — the previous formatting, in the text editor example — at the moment execute() runs, not looked up afterward, since the "before" state may no longer be available by the time undo is actually called.
▲ Trade-off — commands compose cleanly into a single macro command
Since every command satisfies the same one-method interface, a MacroCommand can hold a List<Command> and call execute() on each in sequence, while itself satisfying Command. This is exactly what "macro recording" in an IDE or word processor does underneath: record a sequence of individual commands, then replay them as one. It's a genuine strength of the pattern, but it's worth remembering a macro command's own undo needs to reverse its component commands in the opposite order they were originally executed.
◆ Where this pattern actually shows up
java.lang.Runnable— a functional interface with a single no-argumentrun()method is structurally identical toCommand'sexecute(). Passing aRunnableinto anExecutorServiceor aThreadis handing over a self-contained, executable request without the executor knowing what it actually does.java.util.concurrent.Callable— the same idea, extended to support a return value and checked exceptions, used throughout the executor framework for submitted tasks.- GUI frameworks — buttons, menu items, and keyboard shortcuts in real editors and IDEs trigger generic command objects rather than hardcoded logic, exactly as built in this topic.
- Undo/redo systems —
javax.swing.undo.UndoableEditandUndoManagerare a direct, built-in Command-with-undo implementation in the Java standard library. - Task queues and job scheduling — a queued background job is a Command object sitting in a queue, waiting to be picked up and executed by a worker that has no idea what the job actually does.
- Macro recording in IDEs and word processors — recording a sequence of user actions as individual command objects, then replaying the whole sequence later as one composite action, exactly the MacroCommand idea covered in this topic's edge cases.
Q: What does the Command pattern fundamentally turn a request into? : A full object with a standard execute() method, instead of a raw method call that disappears the instant it finishes running.
Q: In a Button-and-TextEditor example, what are the Invoker and the Receiver, and how do they differ? : The Button is the Invoker — it triggers execute() without knowing what the command actually does. TextEditor is the Receiver — it holds the real methods (makeBold(), etc.) that do the actual work. The concrete command sits between them, bound to one specific receiver method.
Q: Why does Button hold a Command instead of a TextEditor, and what does that specifically buy? : It lets Button ship as a genuinely reusable, application-agnostic class. The same Button object can be repointed at any command for any application, at runtime, without Button itself ever being edited or recompiled.
Q: What would need to change to support undo, and why can't the current Command interface do it? : Command would need an undo() method, and each concrete command would need to capture whatever state is required to reverse itself at the moment execute() runs. The current interface only has execute(), with no mechanism to reverse or remember prior state.
Q: How would you implement macro recording using this pattern? : A MacroCommand class implementing Command, holding a List, whose execute() calls execute() on each command in sequence — itself satisfying the same interface it's composed of.
Want a visual for this concept?
Generate a diagram tailored to “Command Pattern” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →