creational

Command

Encapsulate a request as an object for queuing, logging, and undoable operations.

Normally you call a method and it runs immediately. Sometimes that is not enough.

You may need to queue the action for later, undo it, log it, or retry it after a failure. You cannot do any of that with a plain method call, because once it runs there is nothing left to hold.

Command turns the action into an object. Now it can be stored in a list, passed around, saved, and executed whenever you choose.

A restaurant order slip — the waiter hands the slip to the kitchen. Slips can be queued or cancelled.

Key Concepts

1
Each command implements a small interface, usually with an execute() method.
execute()
2
The command holds everything it needs: which object to act on and the arguments. It is self-contained, so whoever runs it needs to know nothing about it.
3
Because commands are objects, you can keep them in a queue and run them later, or in a list and replay them.
4
For undo, add an undo() method and keep a history stack. Store the values needed to reverse the change, not a reference to state that may have moved on since.
undo()

When to use it

  • Text editors (undo/redo)
  • Task queues and job schedulers
  • Transaction management and rollback
  • Macro recording

Watch out for

  • Every action becomes a class, so the count grows quickly for what may be one-line operations
  • Undo is only as good as the state you captured — commands that store a reference to mutable state rather than a snapshot will undo to the wrong value
  • Queued or persisted commands must stay deserialisable as the code evolves; a renamed field can make yesterday's queued command unreplayable
java
public interface Command {
    void execute();
    void undo();
}
public class InsertTextCommand implements Command {
    private final TextEditor editor;
    private final String text;
    private final int pos;
    public InsertTextCommand(TextEditor e, String t, int p) {
        this.editor = e; this.text = t; this.pos = p;
    }
    public void execute() { editor.insert(text, pos); }
    public void undo() { editor.delete(pos, text.length()); }
}
public class History {
    private final Deque<Command> stack = new ArrayDeque<>();
    public void execute(Command c) { c.execute(); stack.push(c); }
    public void undo() { if (!stack.isEmpty()) stack.pop().undo(); }
}