Real-world combination
Undo/Redo = Command + Memento
Command turns each action into an object with execute()/undo(); Memento lets it snapshot exact state to restore — together they give clean, multi-level undo/redo.
✗ Problem
One state slot can't do multi-level undo
A naive editor keeps a single lastState. It remembers exactly one step back —
no stack, no redo, and every action needs a hand-written inverse.
class Editor {
lastState = null;
type(s) {
this.lastState = this.text; // only ONE slot
this.text += s;
}
undo() {
this.text = this.lastState; // 2nd undo? redo? ✗
}
}
One variable = one step of history. Re-deriving each action's inverse by hand
is error-prone and doesn't scale to redo.
✓ The combination
→
→
↑ state
Two patterns, one job each
Command wraps each action as an object with
execute()/undo(); Memento is the
snapshot it captures so undo restores state exactly — no manual inverse logic.
class Command {
execute(editor) {
this.before = editor.snapshot(); // Memento
this.mutate(editor.state);
this.after = editor.snapshot();
}
undo(editor) { editor.restore(this.before); }
redo(editor) { editor.restore(this.after); }
}
// Invoker
undoStack.push(cmd);
redoStack = []; // new action clears redo
Invoker
undo/redo stacks
Command
execute() / undo()
Memento
snapshot
Editor
originator
✓ See it live
Type, bold, clear — then rewind
Each action pushes a Command onto the undo stack, snapshotting state first.
Undo pops it back onto redo; redo replays its captured "after" state.
(empty)
Undo stack
Redo stack
undo:0 · redo:0
✓ Takeaway
Why two patterns beat one
- Multi-level undo/redo falls out for free — it's just push/pop on two stacks of commands.
- Command gives every action a uniform
execute()/undo()shape the invoker can queue, log, or replay. - Memento guarantees undo restores the exact prior state, no hand-written inverse math needed.
- Real uses: text editors, Photoshop's history panel, IDE undo, form wizards with "back".
🎯 Combines: Command (encapsulate + reverse each action) + Memento (restore exact prior state), coordinated by an invoker holding undo/redo stacks.
Back to all topics →