The Command pattern encapsulates a request as an object, letting you parameterize clients with different requests, queue operations, log requests, and support undoable operations. It decouples the object that invokes the operation from the one that performs it.

Intent and Motivation

Intent: Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Motivation: A text editor’s menu items (Copy, Paste, Delete) should not be hard-wired to document.copy() calls — the same menu slot might invoke different actions depending on context. Command wraps each action in an object with execute() and undo() methods. The UI stores Command references, enabling undo stacks, macro recording, and remote command execution. The invoker (menu, button, scheduler) does not know the receiver’s internals.

Commands are the backbone of CQRS architectures, job queues, and transactional systems.

Structure (UML-like)

  ┌──────────┐  execute()   ┌──────────────┐
│  Invoker │ ───────────► │   Command    │ (interface)
└──────────┘              ├──────────────┤
                          │ + execute()  │
                          │ + undo()     │
                          └──────▲───────┘
                                 │ implements
                          ┌──────┴───────┐
                          │ConcreteCommand│
                          ├──────────────┤
                          │ - receiver   │
                          │ + execute()  │ ── delegates ──► ┌──────────┐
                          │ + undo()     │                  │ Receiver │
                          └──────────────┘                  ├──────────┤
                                                            │ + action()│
                                                            └──────────┘
  

Participants:

  • Command — declares execute() (and optionally undo()).
  • ConcreteCommand — binds a Receiver to an action; implements execute/undo.
  • Receiver — knows how to perform the actual work.
  • Invoker — asks the command to execute; may store command history for undo.
  • Client — creates and configures ConcreteCommand objects.

Java Example

  // Receiver
class TextEditor {
    private final StringBuilder content = new StringBuilder();

    void insert(String text) { content.append(text); }
    void delete(int length) {
        int start = Math.max(0, content.length() - length);
        content.delete(start, content.length());
    }
    String getContent() { return content.toString(); }
}

// Command
interface Command {
    void execute();
    void undo();
}

class InsertCommand implements Command {
    private final TextEditor editor;
    private final String text;

    InsertCommand(TextEditor editor, String text) {
        this.editor = editor;
        this.text = text;
    }

    public void execute() { editor.insert(text); }
    public void undo() { editor.delete(text.length()); }
}

// Invoker
class CommandHistory {
    private final java.util.Stack<Command> history = new java.util.Stack<>();

    void execute(Command cmd) {
        cmd.execute();
        history.push(cmd);
    }

    void undo() {
        if (!history.isEmpty()) history.pop().undo();
    }
}

// Usage
TextEditor editor = new TextEditor();
CommandHistory history = new CommandHistory();
history.execute(new InsertCommand(editor, "Hello "));
history.execute(new InsertCommand(editor, "World"));
System.out.println(editor.getContent()); // Hello World
history.undo();
System.out.println(editor.getContent()); // Hello 
  

JavaScript Example

  // Receiver
const light = {
  isOn: false,
  turnOn() { this.isOn = true; console.log('Light ON'); },
  turnOff() { this.isOn = false; console.log('Light OFF'); }
};

// Commands
const commands = {
  turnOn: {
    execute() { light.turnOn(); },
    undo() { light.turnOff(); }
  },
  turnOff: {
    execute() { light.turnOff(); },
    undo() { light.turnOn(); }
  }
};

// Invoker with undo stack
const remote = {
  history: [],
  run(command) {
    command.execute();
    this.history.push(command);
  },
  undo() {
    const cmd = this.history.pop();
    if (cmd) cmd.undo();
  }
};

remote.run(commands.turnOn);
remote.run(commands.turnOff);
remote.undo(); // Light ON
  

Real-World Use Cases

Framework / System Usage
Java Runnable / Callable Encapsulates work as objects submitted to thread pools.
Swing Action interface Menu items and toolbar buttons bound to Command objects.
CQRS / Event Sourcing Commands represent state-changing intentions; events record results.
Redis / Sidekiq job queues Jobs are serialized command objects processed asynchronously.
Redux dispatch(action) Actions are command objects processed by reducers.
JUnit @Test methods Test runner invokes test commands reflectively.

Pros and Cons

Pros Cons
Decouples invoker from receiver — swap commands at runtime Many command classes for simple operations
Easy to add new commands without changing existing code Undo/redo requires memento-like state tracking
Supports undo, redo, logging, and queuing naturally Command object overhead for trivial operations
Enables macro composition (composite commands) Complex undo with dependent commands is hard
Supports transactional batching of commands Debugging indirect invocation can be harder

When to Use vs When NOT to Use

Use when:

  • You need to parameterize objects with operations to perform.
  • You need to queue, schedule, or log operations.
  • You need to support undo/redo.
  • You want to structure a system around invocable command objects (CQRS, job systems).

Do NOT use when:

  • Operations are simple and unlikely to need undo, queuing, or parameterization.
  • Direct method calls are clear and sufficient.
  • The overhead of command objects outweighs flexibility benefits.
  • Synchronous, one-off operations with no audit trail requirement.

Common Mistakes

  1. Commands with business logic — commands should delegate to receivers, not contain domain logic.
  2. Broken undo semanticsundo() must exactly reverse execute() including side effects.
  3. Not making commands immutable — command state should be fixed at creation time.
  4. Invoker knowing receiver type — breaks decoupling; invoker should only know the Command interface.
  5. Composite commands without atomic undo — macro undo must reverse all sub-commands in order.
  • Memento — stores state for undo; often used with Command to save receiver state before execute.
  • Composite — macro commands are composites of individual commands.
  • Strategy — both encapsulate behavior in objects; Command focuses on request/invocation, Strategy on algorithm selection.
  • Chain of Responsibility — commands can be passed along handler chains.
  • Observer — commands can trigger observer notifications after execution.