Encapsulate a request as an object, allowing you to parameterize clients, queue operations, log history, and support undoable actions.
The Command pattern is a behavioral design pattern that turns a request into a standalone object. That object contains everything needed to perform the action — the receiver, the method to call, and any arguments. This lets you treat requests as data: store them, pass them around, queue them, log them, and reverse them.
Think of a restaurant order slip: a waiter doesn't cook the food — they take your order, write it on a slip (the command object), and hand it to the kitchen (the receiver). The slip can be queued, prioritised, or cancelled. The waiter doesn't need to know how to cook.
In software, this is the foundation for undo/redo, transaction rollback, macro recording, task queues, and any feature where actions need to be stored, deferred, or reversed.
Key Idea: Encapsulate actions as objects. This decouples the sender (who triggers the action) from the receiver (who executes it), and enables undo, queuing, and logging.
Declares execute() and (optionally) undo() methods. All concrete commands implement this interface, making them interchangeable from the invoker's perspective.
Implements the Command interface. Holds a reference to the Receiver and maps execute()/undo() to specific receiver method calls. Also stores any data needed to reverse the operation.
The object that knows how to perform the actual work. The concrete command delegates to the receiver. The receiver can be any class — TextEditor, Light, BankAccount, etc.
Stores and triggers commands. It doesn't know anything about the concrete command or receiver — it just calls execute(). The invoker can maintain a history stack for undo/redo.
Creates concrete command objects, sets their receivers, and gives them to the invoker. The client wires everything together but doesn't execute commands directly.
Without Command, the sender (e.g., a button) directly calls the receiver's method. This means:
// Button directly calls receiver — tightly coupled
class SaveButton {
void onClick() {
editor.save(); // Coupled! No undo, no queuing
}
}
class UndoButton {
void onClick() {
// Where does undo history live? Who tracks it?
// No standard mechanism — must reinvent every time
}
}// Button just invokes a command — completely decoupled saveButton.setCommand(new SaveCommand(editor)); undoButton.setCommand(() -> history.undo()); // Undo is automatic — history tracks all commands
Undo/Redo is the killer feature of the Command pattern. Here's how it works with two stacks:
Run the command and push it onto the undo stack. Clear the redo stack (new action invalidates redo history).
Pop from the undo stack, call undo(), push to redo stack. Each command is responsible for reversing its own action.
Pop from the redo stack, call execute() again, push back to undo stack. No special logic needed.
Undo / Redo Stack Flow
// Command Pattern — Text Editor with Undo/Redo
import java.util.Stack;
// ─── Command interface ────────────────────────────────────────
interface Command {
void execute();
void undo();
}
// ─── Receiver — the object that does the actual work ──────────
class TextEditor {
private StringBuilder text = new StringBuilder();
public void insertText(int pos, String content) {
text.insert(pos, content);
System.out.println("[Editor] Text: "" + text + """);
}
public void deleteText(int pos, int length) {
text.delete(pos, pos + length);
System.out.println("[Editor] Text: "" + text + """);
}
public String getText() { return text.toString(); }
}
// ─── Concrete Commands ────────────────────────────────────────
class InsertCommand implements Command {
private TextEditor editor;
private int position;
private String content;
public InsertCommand(TextEditor editor, int position, String content) {
this.editor = editor;
this.position = position;
this.content = content;
}
@Override
public void execute() {
editor.insertText(position, content);
}
@Override
public void undo() {
// Reverse: delete what was just inserted
editor.deleteText(position, content.length());
}
}
class DeleteCommand implements Command {
private TextEditor editor;
private int position;
private int length;
private String deletedText; // saved for undo
public DeleteCommand(TextEditor editor, int position, int length) {
this.editor = editor;
this.position = position;
this.length = length;
}
@Override
public void execute() {
// Save deleted content before removing it
deletedText = editor.getText().substring(position, position + length);
editor.deleteText(position, length);
}
@Override
public void undo() {
editor.insertText(position, deletedText);
}
}
// ─── Invoker — manages command history and execution ──────────
class CommandHistory {
private Stack<Command> undoStack = new Stack<>();
private Stack<Command> redoStack = new Stack<>();
public void execute(Command command) {
command.execute();
undoStack.push(command);
redoStack.clear(); // new action clears redo history
}
public void undo() {
if (!undoStack.isEmpty()) {
Command command = undoStack.pop();
command.undo();
redoStack.push(command);
System.out.println("[History] Undo performed");
}
}
public void redo() {
if (!redoStack.isEmpty()) {
Command command = redoStack.pop();
command.execute();
undoStack.push(command);
System.out.println("[History] Redo performed");
}
}
}
// ─── Client ───────────────────────────────────────────────────
public class Application {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
CommandHistory history = new CommandHistory();
history.execute(new InsertCommand(editor, 0, "Hello"));
history.execute(new InsertCommand(editor, 5, " World"));
history.execute(new DeleteCommand(editor, 0, 5));
// Text: " World"
history.undo(); // Restores "Hello World"
history.undo(); // Restores "Hello"
history.redo(); // Re-applies " World" → "Hello World"
}
}Any editor or interactive application that needs history — text editors, drawing apps, IDEs, spreadsheets.
TextEditor, PhotoEditor, SpreadsheetAppDatabase-style operations where a failure mid-way should undo all previous steps atomically.
BankTransfer, OrderPlacement, BatchUpdateWhen operations need to be queued, deferred, or executed at a specific time rather than immediately.
JobQueue, TaskScheduler, BackgroundWorkerRecord a sequence of user actions and replay them — used in automation, testing, and productivity tools.
MacroRecorder, TestPlayback, ScriptBuilderDecouple UI controls from business logic — a button, keyboard shortcut, and menu item all trigger the same command object.
SaveCommand, CopyCommand, PasteCommandEvery git commit is a Command object — it records the change (execute) and knows how to reverse itself (git revert). Git's entire history model is built on Command.
BEGIN, COMMIT, ROLLBACK is a Command pattern implementation. Each statement is a command that can be committed (execute) or rolled back (undo) atomically.
Redux actions are Command objects — plain JS objects describing what happened. The reducer's switch-case maps each action to a state transformation. Time-travel debugging is undo/redo via Command.
Runnable and Callable are the Command pattern. They encapsulate work to be done and are passed to an Executor (the invoker) for queuing and execution on a thread pool.