Back to Articles
📄
Command patterndesign patternundoinvokerreceivermacroqueuesoftware architecture

What Is the Command Pattern and When Should You Use It?

Turn actions into first‑class objects to queue, log, undo, or replay them without tying callers to implementations. The Command pattern cleanly separates triggers from work, making UI shortcuts, macros, and audit trails effortless.

What Is the Command Pattern and When Should You Use It?

The Command pattern represents a request as an object, allowing an application to parameterize, queue, log, repeat, or undo an action without coupling the trigger to the receiver. By turning a request into a first‑class object, the pattern lets an application maintain history, schedule work, and keep the caller independent of the implementation.

The Core Idea

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

const command = new BoldCommand(editor);
manager.execute(command);
manager.undo();

The manager only needs to know the command's interface; it doesn't need to understand text editing or file deletion specifics. In other words, the manager can invoke any command that conforms to the interface without caring whether the command bolds text, deletes a file, or performs any other operation.

The Participants

  • Command: defines operations such as execute and, when appropriate, undo.
    It establishes the contract that all concrete commands must follow.

  • Concrete Command: holds the receiver and request data.
    It encapsulates the details needed to carry out the action.

  • Invoker: executes commands and can maintain a history.
    It acts as the client‑facing component that triggers the command.

  • Receiver: performs the actual work.
    The receiver knows how to carry out the operation that the command requests.

class CommandManager {
  private history: Command[] = [];

  execute(command: Command) {
    command.execute();
    this.history.push(command);
  }

  undo() {
    this.history.pop()?.undo();
  }
}

For an undo operation to be effective, it must capture enough state to reverse the operation correctly. Simply calling the same method twice is not always a valid way to undo an action. Therefore each concrete command must store the information required to restore the previous state before it modifies anything.

Applications

Commands are particularly useful for UI actions with multiple triggers, macro operations, background queues, and audit logs:
They let disparate parts of the UI invoke the same behavior without duplicating code, and they provide a natural way to record what happened for later replay or analysis.

class MacroCommand implements Command {
  constructor(private commands: Command[]) {}

  execute() {
    for (const command of this.commands) command.execute();
  }

  undo() {
    for (const command of [...this.commands].reverse()) command.undo();
  }
}

They can also support rollback workflows. However, database transactions and distributed compensation require stronger guarantees than an in‑memory command list can provide. In practice, a simple command list can undo changes only while the program remains alive; persistent or distributed systems need transactional support beyond what the pattern alone offers.

When to Use It

Use the Command pattern when actions need to be queued, serialized, audited, composed, or undone. Avoid it for simple one‑off calls where object creation and history management would only add unnecessary complexity.

For a single UI callback, closures are often sufficient. Command objects become more valuable when the same action is invoked from multiple places or has a lifecycle of its own. In those cases the command can be stored, passed around, or scheduled for later execution.

Memento captures state snapshots, while Command stores actions. Composite can represent a macro of commands. Strategy encapsulates an algorithm, whereas Command encapsulates a request. Thus each pattern solves a distinct problem, but they can be combined, for example, a Composite command may use Memento objects to restore state.

The Bottom Line

Command makes actions first‑class objects, providing a practical solution when an application needs to maintain history, manage queues, handle macros, or achieve a clean separation between an action's trigger and its implementation.

Sources & References

  1. [1]
  2. [2]
  3. [3]

Comments (0)

Loading comments...
What Is the Command Pattern and When Should You Use It? | Arne's Blog