Skip to article
ALGORITHMICSPatterns
Patterns5 min read

Memento

A snapshot that only its owner can read — and why undo usually wants commands instead.


Save an object’s state so you can restore it later, without the saver being able to poke at the internals.

The three roles

/** Opaque on purpose: the caretaker can hold it and cannot read it. */
class EditorMemento {
constructor(
private readonly content: string,
private readonly cursor: number,
) {}
// No getters. Only Editor knows what is inside, via the restore method below.
}
class Editor { // originator
private content = '';
private cursor = 0;
save(): EditorMemento {
return new EditorMemento(this.content, this.cursor);
}
restore(memento: EditorMemento) {
// In TypeScript, private is per-class, so Editor cannot read another
// class's privates — hence the memento exposing a package-level accessor,
// or (more usually) being a nested class.
({content: this.content, cursor: this.cursor} = memento.read());
}
}
class History { // caretaker
private states: EditorMemento[] = [];
push(memento: EditorMemento) { this.states.push(memento); }
pop(): EditorMemento | undefined { return this.states.pop(); }
}

Originator makes and accepts snapshots. Memento is the snapshot. Caretaker stores them and never looks inside.

hello

cursor 5

caretaker — holds, cannot read

nothing saved yet

Each save is an opaque blob. The caretaker can hold it, list it, and hand it back — it has no accessor for text or cursor, so it cannot come to depend on how the editor stores things.

The cost, which is usually the deciding factor

A memento is a full copy. Undo depth of 100 on a 10 MB document is a gigabyte.

That is why editors that actually ship rarely use plain mementos:

When it is the right choice

Memento is genuinely simpler than Command when:

The last one is the strongest reason. “Save game” is a memento; “undo” is usually a command.