Skip to contentJMRG
All posts

Command Pattern: Actions as Objects

design-patternsbehavioralcommand

Intent

Command encapsulates a request as an object, allowing you to parameterize clients with different requests, queue or log requests, and support reversible operations (undo/redo).

The Problem

Imagine a text editor. Without Command, undo code would be a mess:

// Without pattern: global state and scattered logic
let previousContent: string;

function bold() {
  previousContent = content;
  content = `<b>${content}</b>`;
}

function undo() {
  content = previousContent; // What about multiple undos?
}

The Solution: Command

classDiagram
    class Command {
        <<interface>>
        +execute(): void
        +undo(): void
    }

    class Invoker {
        -history: Command[]
        +executeCommand(cmd)
        +undoLast()
    }

    Command <|.. ConcreteCommand
    Invoker --> Command

TypeScript Implementation

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

class InsertTextCommand implements Command {
  constructor(
    private document: TextDocument,
    private position: number,
    private text: string
  ) {}

  execute(): void {
    this.document.insertAt(this.position, this.text);
  }

  undo(): void {
    this.document.deleteRange(this.position, this.position + this.text.length);
  }
}

class TextEditor {
  private history: Command[] = [];
  private redoStack: Command[] = [];

  executeCommand(cmd: Command): void {
    cmd.execute();
    this.history.push(cmd);
    this.redoStack = [];
  }

  undo(): boolean {
    const cmd = this.history.pop();
    if (!cmd) return false;
    cmd.undo();
    this.redoStack.push(cmd);
    return true;
  }

  redo(): boolean {
    const cmd = this.redoStack.pop();
    if (!cmd) return false;
    cmd.execute();
    this.history.push(cmd);
    return true;
  }
}

When to Use

Situation Recommendation
Undo/Redo operations ✅ Recommended
Task queues ✅ Recommended
Transactions ✅ Recommended
Simple operations without history ❌ Overkill

Conclusion

Command transforms operations into first-class objects, enabling undo, queues, and composition.