Coding · Design patterns
Memento pattern explained with examples
Short answer
Memento is a behavioral design pattern that captures an object's internal state in a snapshot object, called a memento, so that the object can be restored to that state later. The object that owns the state (the originator) creates and restores mementos, while another object (the caretaker) only stores them and never looks inside. It is the standard way to implement undo, checkpoints and save games without breaking encapsulation.
Intent and the problem it solves
Intent: without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later. Memento is one of the behavioral patterns in the Gang of Four (GoF) book.
Imagine a drawing app where a shape has a position, size, color and a list of private, derived values used for rendering. You want an undo button. The undo manager could copy the shape's fields itself, but then it must know every private field, and every time the shape class changes, the undo manager breaks. Making all fields public just for undo would let any code put the shape into an invalid state.
Memento solves this by letting the shape itself produce a snapshot. Only the shape knows what is inside the snapshot and how to restore from it. The undo manager treats snapshots as opaque objects: it stores them in a list and hands one back when the user presses undo.
Structure and participants
| Role | Responsibility |
|---|---|
| Originator | The object whose state is saved; creates a memento of its current state and restores itself from a memento |
| Memento | An immutable snapshot of the originator's state; exposes nothing useful to other objects |
| Caretaker | Decides when to save and when to restore, and keeps the mementos (for example in a stack), but never reads or changes their contents |
The key idea is two interfaces: a wide one for the originator, which can read the saved state, and a narrow one for everyone else, which can only hold the memento.
TypeScript implementation
The memento class uses JavaScript private fields (#state), so the caretaker cannot read the stored data from the memento object. Reading goes through the static method EditorMemento.read, which only the editor calls. In a real project, put the memento class in the same module as the editor and do not export it, so other modules can hold mementos but never open them.
type EditorState = { text: string; cursor: number };
class EditorMemento {
readonly #state: EditorState;
constructor(state: EditorState) {
this.#state = { ...state }; // copy, so later edits do not change the snapshot
}
static read(m: EditorMemento): EditorState {
return { ...m.#state };
}
}
class Editor {
private state: EditorState = { text: "", cursor: 0 };
type(words: string) {
const text = this.state.text + words;
this.state = { text, cursor: text.length };
}
get text() { return this.state.text; }
save(): EditorMemento { return new EditorMemento(this.state); }
restore(m: EditorMemento) { this.state = EditorMemento.read(m); }
}
class History {
private stack: EditorMemento[] = [];
constructor(private editor: Editor) {}
backup() { this.stack.push(this.editor.save()); }
undo() { const m = this.stack.pop(); if (m) this.editor.restore(m); }
}
const editor = new Editor();
const history = new History(editor);
history.backup(); editor.type("Hello");
history.backup(); editor.type(" world");
console.log(editor.text); // Hello world
history.undo();
console.log(editor.text); // Hello
history.undo();
console.log(JSON.stringify(editor.text)); // ""History is the caretaker. It calls backup() before each change and undo() to go back, but it never sees text or cursor. If you later add a selection range to EditorState, History does not change.
Memento vs Command for undo
There are two common ways to implement undo, and they are often combined:
| Approach | What is stored | Good when | Cost |
|---|---|---|---|
| Memento | A snapshot of the whole state before each change | Changes are hard to reverse, or state is small | Memory grows with the size of the state times the number of steps |
| Command | The operation and enough data to reverse it | Each operation has a simple inverse | Each command needs correct undo logic |
A practical compromise: store commands for most steps and a full memento every N steps, or store only the part of the state that a command changes.
When to use it and when not to
- Use it for undo, redo, checkpoints, save games and "cancel" buttons on forms that should roll back edits.
- Use it for transactions in memory: snapshot before a risky operation and restore if it fails.
- Use it when the caretaker must not depend on the originator's internal fields.
- Do not use it when the state is very large and changes often, unless you limit the history length or store only differences.
- Do not add the full ceremony when the state is already a plain immutable value. With immutable data, an old value is already a snapshot, and keeping a list of previous values is enough.
Real-world uses
- The browser History API:
history.pushState(state, "", url)stores a state object for each history entry, and thepopstateevent hands it back when the user navigates. - Redux and similar stores keep immutable state snapshots, which tools use for time-travel debugging.
- SQL databases support
SAVEPOINTinside a transaction, so work can be rolled back to a named point. - Text editors, graphics programs and games save snapshots for undo, autosave and save slots.
Related patterns
| Pattern | How it relates to Memento |
|---|---|
| Command | Command can undo by reversing an operation; it can also store a memento taken before it ran and restore it in undo. |
| Prototype | Prototype clones a whole object to create a new one; a memento stores state to restore the same object later. |
| Iterator | An iterator can expose its current position as a memento so a traversal can resume later. |
| State | State changes the object's behavior when its state changes; Memento only records and restores the data. |
FAQ
What is the difference between originator and caretaker?
The originator owns the state and is the only object that can create a memento and restore from it. The caretaker decides when to save and restore and keeps the mementos, but treats them as opaque.
Does Memento break encapsulation?
No, that is its purpose. The originator's internal fields stay private, and the memento hides them from the caretaker, so only the originator can read the saved state.
How do I limit memory use with Memento?
Keep a maximum number of snapshots and drop the oldest, store only the changed part of the state, or combine mementos with commands that record small changes.
Is JSON serialization a memento?
Serializing state to JSON can be the storage format of a memento, and it is useful for saving to disk. The pattern itself is about who creates, keeps and restores the snapshot, not the format.