One-line Definition
Encapsulates an operation as an object, allowing requests to be queued, logged, or undone transparently.
Problem
Suppose you are building a text editor with UI buttons for Copy, Paste, and Undo. If the "Copy" button directly calls Editor.copy(), the button is tightly coupled to the editor. If you later want to implement keyboard shortcuts that do the exact same thing, you have to duplicate the logic. Furthermore, how do you implement "Undo" if actions are just immediate method calls? The Command Pattern solves this by turning every action into a standalone object that can be executed, stored in a history stack, or reversed.
Real-world Analogy
At a restaurant, you don't walk into the kitchen and cook your food. You tell the waiter "I'd like a steak." The waiter writes your order (command) on a slip. The slip goes to the kitchen (receiver). The waiter (invoker) doesn't know how to cook — they just pass the command. If you change your mind, the waiter can cancel the slip.
Structure
- Client
- Creates Command objects and sets their receivers.
- Invoker
- Holds a reference to a Command and triggers its execution (e.g., a GUI Button or a History Stack).
- Command
- Interface declaring an
execute()method (and optionallyundo()).
- Interface declaring an
- ConcreteCommand
- Binds the Receiver to an action. Implements
execute()by calling the Receiver's methods.
- Binds the Receiver to an action. Implements
- Receiver
- The object that actually performs the business logic (e.g., the TextEditor).
Diagram
classDiagram
class Client {
}
class Invoker {
-Command command
+executeCommand()
}
class Command {
<<interface>>
+execute()
+undo()
}
class ConcreteCommand {
-Receiver receiver
+execute()
+undo()
}
class Receiver {
+action()
}
Client --> Invoker
Client --> ConcreteCommand
Invoker o-- Command : stores
ConcreteCommand ..|> Command
ConcreteCommand --> Receiver : calls
Code Walkthrough
Notice how the EditorInvoker maintains a history stack of Command objects. It doesn't know what the commands actually do; it just calls execute() and undo().
interface Command {
void execute();
void undo();
}
class TextEditor {
private StringBuilder text = new StringBuilder();
public void write(String content) {
text.append(content);
System.out.println("Text: " + text);
}
public void eraseLast(int count) {
int start = Math.max(0, text.length() - count);
String erased = text.substring(start);
text.delete(start, text.length());
System.out.println("Erased '" + erased + "'. Text: " + text);
}
}
class WriteCommand implements Command {
private final TextEditor editor;
private final String content;
public WriteCommand(TextEditor editor, String content) {
this.editor = editor;
this.content = content;
}
@Override
public void execute() { editor.write(content); }
@Override
public void undo() { editor.eraseLast(content.length()); }
}
class EditorInvoker {
private final Stack<Command> history = new Stack<>();
public void executeCommand(Command command) {
command.execute();
history.push(command);
}
public void undo() {
if (!history.isEmpty()) {
Command command = history.pop();
command.undo();
} else {
System.out.println("Nothing to undo");
}
}
}
class Main {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
EditorInvoker invoker = new EditorInvoker();
invoker.executeCommand(new WriteCommand(editor, "Hello "));
invoker.executeCommand(new WriteCommand(editor, "World"));
invoker.executeCommand(new WriteCommand(editor, "!"));
System.out.println("--- Undoing ---");
invoker.undo(); // Removes "!"
invoker.undo(); // Removes "World"
}
}
Bad vs Good
Bad Approach
Problems
- The UI component (Button) is tightly coupled to the business logic (Editor).
- No way to implement an "Undo" feature because method calls are immediately forgotten.
class Button {
private final TextEditor editor;
public Button(TextEditor editor) { this.editor = editor; }
public void onClick(String text) {
editor.write(text); // Direct call — no undo, no history
}
}
Better Approach
Improvements
- The UI (Button/Invoker) only knows about the
Commandinterface. - You gain full undo/redo history completely for free.
class Button {
private final Command command;
public Button(Command command) { this.command = command; }
public void onClick() {
command.execute(); // Decoupled — undo, history, queue all possible
}
}
Pros vs Cons
| Pros | Cons |
|---|---|
| Fully decouples the UI (invokers) from the business logic (receivers) | Requires creating a new class for every distinct action |
| Enables powerful features like Undo, Redo, and Macro recording | Can significantly bloat the codebase for simple applications |
| Commands can be serialized to disk or placed in a queue | Managing complex state for undo() operations is difficult |
| Adheres strictly to the Single Responsibility Principle | |
| Easy to add new commands without modifying existing code |
When to Use
- You need to support undo/redo operations.
- You need to parameterize objects with actions (e.g., assigning different actions to UI buttons).
- You want to queue tasks, schedule their execution, or execute them remotely.
- You want to implement macros (a sequence of commands executed together).
When Not to Use
- The application is incredibly simple, and commands are just direct wrappers around trivial method calls.
- You have no need for undo functionality, queuing, or decoupling UI from business logic.
Real-world Examples
java.lang.Runnable(The classic Command interface for threading)javax.swing.Action(Swing's implementation of the Command pattern for UI actions)- Thread Pools and Task Executors (which consume Queues of Command objects).
Key Takeaway
The Command Pattern treats method calls as first-class objects. By wrapping a request in an object, you decouple the sender from the receiver and gain the ability to store, queue, and reverse operations. Use it for complex UIs or transactional systems, but stick to direct method calls if you don't need history or queuing.