BEHAVIORAL PATTERNS / OBJECT DESIGN BRIEF

Command pattern

The Command pattern turns a request into an object that contains everything needed to perform it: the action, the receiver, and the parameters.

IntermediatePhase 06 / Topic 3 of 10ResponsibilitiesCollaborationsExtensibility
01

Overview

The Command pattern turns a request into an object that contains everything needed to perform it: the action, the receiver, and the parameters. Because a command is an object, it can be queued, logged, scheduled, retried, sent over a network, and undone.

The invoker (a button, a scheduler, a remote control) calls command.execute() without knowing what it does. Commands with undo() let editors, spreadsheets, and games support undo/redo stacks. Job queues and event-sourced systems are large-scale versions of the same idea.

A restaurant order ticket

The waiter writes the order on a ticket (command) and places it on the rail. The cook (receiver) executes it later. The ticket can be queued, reordered, or cancelled without the waiter knowing how to cook.

02

When to use it

  • Undo/redo is required.
  • Operations must be queued, scheduled, or retried.
  • UI actions (buttons, shortcuts, menus) should share the same operations.
  • Macro recording or audit logs of actions.
03

Where it shows up in interviews

Undo / redo

Recognize it when: users can reverse actions.

  • Design a text editor
  • Design a drawing app
  • Design a spreadsheet
Queued operations

Recognize it when: actions executed later or remotely.

  • Design a task scheduler
  • Design a smart home remote
  • Design a job queue
04

Where it is used in real software

Editor undo stacks

VS Code, Photoshop, and Figma record operations as commands with inverse actions.

Java Runnable and ExecutorService

Runnable tasks are commands submitted to a thread pool for later execution.

Redux actions

Actions are serializable command-like objects dispatched to reducers, enabling time-travel debugging.

05

Key terms

Command
Object with execute() (and often undo()).
Receiver
The object that does the actual work.
Invoker
Triggers commands without knowing details.
Client
Creates commands and binds them to receivers.
Macro command
A command composed of other commands.
06

How it works, step by step

  1. 1
    Define the Command interface

    execute() and undo().

  2. 2
    Implement concrete commands

    Each stores its receiver and parameters.

  3. 3
    Store undo information

    Previous state or inverse parameters.

  4. 4
    Invoker executes and records history

    Push to an undo stack.

  5. 5
    Undo pops and reverses

    Redo re-executes from a redo stack.

Undo and redo stacks
Step 1 / 4
type 'Hi'
type ' there'
bold
Undo stack
Redo stack

STEP 1Three commands execute; each is pushed onto the undo stack.

07

Text editor history

Document starts empty

Step 1 / 5
ActionDocumentUndo stackRedo stack
Insert 'Hello'Hello[Insert][]
Insert ' World'Hello World[Insert, Insert][]
UndoHello[Insert][Insert ' World']
RedoHello World[Insert, Insert][]
Delete 5 chars, then undoHello World[Insert, Insert][Delete]

NOWAction: Insert 'Hello' | Document: Hello | Undo stack: [Insert] | Redo stack: []

Each command knows how to reverse itself, so history management is generic.

08

Implementation

interface Command { execute(): void; undo(): void } class TextDocument { content = ""; } class InsertText implements Command {  constructor(private doc: TextDocument, private text: string, private at: number) {}  execute() { this.doc.content = this.doc.content.slice(0, this.at) + this.text + this.doc.content.slice(this.at); }  undo() { this.doc.content = this.doc.content.slice(0, this.at) + this.doc.content.slice(this.at + this.text.length); }} class DeleteText implements Command {  private removed = "";  constructor(private doc: TextDocument, private at: number, private length: number) {}  execute() {    this.removed = this.doc.content.slice(this.at, this.at + this.length);    this.doc.content = this.doc.content.slice(0, this.at) + this.doc.content.slice(this.at + this.length);  }  undo() { this.doc.content = this.doc.content.slice(0, this.at) + this.removed + this.doc.content.slice(this.at); }} class Editor {  private undoStack: Command[] = [];  private redoStack: Command[] = [];  run(cmd: Command) { cmd.execute(); this.undoStack.push(cmd); this.redoStack = []; }  undo() { const c = this.undoStack.pop(); if (c) { c.undo(); this.redoStack.push(c); } }  redo() { const c = this.redoStack.pop(); if (c) { c.execute(); this.undoStack.push(c); } }} const doc = new TextDocument();const editor = new Editor();editor.run(new InsertText(doc, "Hello", 0));editor.run(new InsertText(doc, " World", 5));editor.undo(); // "Hello"editor.redo(); // "Hello World"
09

Complexity and performance

Execute / undoO(command work)

Plus O(1) stack ops.

History memoryO(commands x undo data)

Cap history length.

10

Trade-offs

Flexibility vs class count

A class per action adds code; lambdas can replace simple commands without undo.

Undo data vs memory

Storing previous state is simple but memory heavy; storing inverse operations is compact but harder.

11

Variants and related techniques

Macro commands

A composite of commands executed and undone as one.

Command queue / job system

Serialized commands processed by workers.

Command vs Memento for undo

Command stores how to reverse; Memento stores snapshots.

12

Common mistakes

  • Not clearing redo after a new command.

    Fix: New actions invalidate the redo branch.

  • Commands that depend on mutable external state at undo time.

    Fix: Capture needed data at execute time.

13

Interview questions

How would you implement undo/redo in a text editor?

Model each edit as a Command with execute() and undo(); keep an undo stack and a redo stack. Undo pops from undo, reverses, and pushes to redo; any new command clears redo.

Command vs Strategy?

A Strategy is how to do something, chosen and reused by a context. A Command is a specific request to do something, captured as an object to be executed, queued, logged, or undone.

14

Practice problems

ProblemDifficultyWhat it trains
Smart home remote with undoEasyInvoker and receivers.
Drawing app with undo/redo and macrosMediumHistory management.