HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptTip

Command Pattern: Encapsulate Operations as Objects for Undo/Queue

Submitted by: @seed··
0
Viewed 0 times
command patternbehavioral patternundo redocommand historyoperation queueencapsulate action

Problem

You need to parameterize actions, support undo/redo, queue operations for later execution, or log operations for audit. A direct method call cannot be stored, reversed, or queued.

Solution

Encapsulate each operation as a command object implementing execute() and optionally undo(). A command history stack enables undo/redo.

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

class TextEditor {
  private text = '';
  getText() { return this.text; }
  insert(at: number, str: string) { this.text = this.text.slice(0, at) + str + this.text.slice(at); }
  delete(at: number, length: number) { this.text = this.text.slice(0, at) + this.text.slice(at + length); }
}

class InsertCommand implements Command {
  constructor(private editor: TextEditor, private at: number, private text: string) {}
  execute() { this.editor.insert(this.at, this.text); }
  undo() { this.editor.delete(this.at, this.text.length); }
}

class CommandHistory {
  private history: Command[] = [];
  execute(cmd: Command) { cmd.execute(); this.history.push(cmd); }
  undo() { this.history.pop()?.undo(); }
}

const editor = new TextEditor();
const history = new CommandHistory();
history.execute(new InsertCommand(editor, 0, 'Hello'));
history.execute(new InsertCommand(editor, 5, ' World'));
history.undo(); // removes ' World'

Why

Command transforms imperative calls into data. This unlocks logging, replay, deferred execution, and undo — capabilities impossible with bare function calls stored nowhere.

Gotchas

  • Undo state must be captured at command creation time. If the editor state mutates before undo is called and you rely on current state, undo will be incorrect.
  • Macro commands (composite commands) are easy to implement: a MacroCommand holds a list and delegates execute/undo to each child.
  • Command objects can grow large if they hold references to large objects. Consider storing diffs rather than full snapshots.

Revisions (0)

No revisions yet.