Memento Pattern
Without violating encapsulation, capture and externalize an object’s internal state so it can be restored later. The foundation of undo systems, save/load in games, transaction rollback, and browser back buttons.
Why Memento Exists
You are building a text editor. Users type, format, and delete text. They expect Ctrl+Z (undo) to revert the document to its previous state. The naive approach: expose the editor’s internal state (text content, cursor position, selection, formatting) so an external history manager can save and restore it.
What goes wrong:
- Encapsulation violated — all editor fields are public; any code can corrupt the editor’s state at any time
- Tight coupling — the undo manager knows every field name, type, and order; adding “selection range” to the editor requires changing the undo manager
- Fragile serialization — state is stored as a
String[]; one index off and the restore corrupts everything - Security risk — anyone with a reference to the history can tamper with stored state
- No separation of concerns — the editor shouldn’t care about history management; the history manager shouldn’t understand editor internals
This is the problem Memento solves — the editor itself creates an opaque snapshot (memento) of its own state. The caretaker (undo manager) stores mementos without understanding their contents. Only the editor can create or restore from its own mementos. Encapsulation preserved.
What Is Memento?
Memento is a behavioral pattern that captures an object’s internal state into a snapshot object (the memento) without violating encapsulation, so the state can be restored later. The originator (the object whose state we save) creates and restores mementos. A caretaker stores mementos but never inspects or modifies their contents.
— Gamma, Helm, Johnson, Vlissides (1994)
Key insight: Memento is about who has knowledge. Only the originator knows how to serialize and deserialize its own state. The memento is a “black box” to everyone else. This preserves encapsulation while enabling undo/redo, checkpointing, and transaction rollback. The caretaker manages when to save/restore, but not what is saved.
save() — a snapshot of its own stateoriginator.restore(memento)Participants & Structure
| Participant | Role | In the Analogy |
|---|---|---|
| Originator | The object whose state needs to be saved and restored. Creates mementos from its current state. Restores itself from a memento. Only it can read memento contents. | The game engine — creates save files from its internal state and loads from them. |
| Memento | An opaque snapshot of the originator’s state. Should be immutable. Its fields are accessible only to the originator (private inner class or package-private). External code sees only a marker interface. | The save file — contains all game state, encrypted/opaque, can’t be tampered with. |
| Caretaker | Manages memento storage (stack for undo, list for history). Requests saves from the originator, stores the returned memento, and later passes it back for restore. Never inspects memento contents. | The OS / file system — stores save files, lets you pick one to load, but doesn’t understand the data inside. |
- Both support undo. Command stores the operation and its inverse (do/undo).
- Memento stores the full state snapshot.
- Command is efficient when operations are simple and reversible (e.g. “add 5” β “subtract 5”).
- Memento is necessary when operations aren’t easily reversible (e.g. regex find-and-replace on a text document) or when computing the inverse is more expensive than storing the state.
The Pattern In Motion
Scenario: A text editor. The user types, the caretaker (undo manager) saves snapshots, and Ctrl+Z restores the previous state.
editor.save()Snapshot memento containing content="Hello", cursor=5. Returns the opaque snapshot. Caretaker pushes it onto the history stack.content="Hello World", cursor=11. History stack now has 2 mementos. Caretaker doesn’t look inside them.editor.restore(history.pop())content="Hello", cursor=5. State reverted.content or cursor directlyselectionRange) to the editor only requires updating the Snapshot inner class — the caretaker is untouched.- The caretaker decides when to capture snapshots.
- Common strategies: save before every user action (full undo), save at checkpoints (game saves), save on explicit request (Ctrl+S).
- The originator doesn’t know why it’s being saved — separation of concerns.
You Already Use This
Memento appears wherever state needs to be captured and restored without exposing internals — serialization, undo in UI frameworks, and transaction management.
java.io.Serializable — serialization captures an object’s complete state to a byte stream (memento). The object is later restored via deserialization. The byte stream is opaque to external code. This is Memento implemented at the JVM level. javax.swing.undo.UndoManager — Swing’s undo framework. UndoableEdit objects capture state changes. UndoManager (caretaker) stores them in a stack. Calling undo() restores the previous state. Each edit is a memento of the change. java.util.Date (clone as memento) — Date is mutable. Defensive copying (new Date(original.getTime())) creates an implicit memento. The copy preserves state at a point in time; the original can change without affecting the copy. Spring Transaction Management — @Transactional saves the database state (via savepoints). On exception, the transaction rolls back to the savepoint — a memento of the DB state. Connection.setSavepoint() in JDBC is a literal Memento implementation. - Every time you serialize an object (
ObjectOutputStream), you’re creating a memento. - Every time you deserialize, you’re restoring from it.
- The difference: GoF Memento emphasizes encapsulation (only the originator interprets the snapshot), while raw serialization exposes byte structure to anyone who reads the format spec.
Build It Once
Domain: Text Editor with Undo. The TextEditor (originator) has content and cursor position. It creates Snapshot mementos (private inner record). The UndoManager (caretaker) stores snapshots on a stack and invokes undo.
- In Java, the
Snapshotrecord is a private inner class ofTextEditor. - The caretaker holds references typed as
EditorMemento(a marker interface with no methods). - It literally cannot access
contentorcursor. - This is the GoF-recommended approach for maximum encapsulation.
Common Mistakes
- If the memento has public getters (
getContent(),getCursor()), any code can read or modify the snapshot — defeating the entire purpose of the pattern. - Fix: Make the memento a private inner class of the originator. The caretaker sees only a marker interface (
EditorMemento) with zero methods. Only the originator can cast and read the fields.
- If the originator has a
List<String> tagsfield and the memento stores the same reference, changes to the originator’s list corrupt the saved snapshot. - Fix: Always perform a deep copy when creating the memento. Use
List.copyOf(tags)or serialize to an immutable structure. Records with immutable fields (String, int) are naturally safe.
- Developers sometimes serialize the entire object to JSON/bytes and call it “Memento.” While similar, GoF Memento emphasizes encapsulation — the caretaker cannot interpret the snapshot.
- If you serialize to JSON and any code can deserialize and read/modify fields, that’s not true Memento.
- Fix: Encrypt the serialized data or use the private-inner-class approach. The caretaker should be unable to understand the snapshot contents.
- A naive undo stack discards the “undone” memento forever.
- Users expect redo (Ctrl+Y).
- Fix: Use two stacks:
undoStackandredoStack. On undo: save current state to redoStack, restore from undoStack. On redo: save current state to undoStack, restore from redoStack. On new action: clear the redoStack (future history is invalidated).
When To Use Memento
- You need undo/redo and the operations are not easily reversible (e.g. complex text transforms, image filters, graph mutations)
- You want to checkpoint state for rollback (database savepoints, transaction rollback, game saves)
- The originator’s state must remain encapsulated — external code should not know or access the internal fields
- You need multiple snapshots at different points in time (history timeline, branching undo)
- Computing the inverse operation is harder than storing the full state (Command pattern undo is harder when operations are destructive)
- The state is very large and snapshots would consume too much memory (use incremental/delta saves instead)
- Operations are easily reversible — Command with inverse (
do/undo) is more memory-efficient - You don’t need encapsulation — if state is already publicly accessible, a simple copy is sufficient without the pattern formalism
- State changes are rare and simple — a direct backup is simpler than the Originator/Memento/Caretaker architecture
| Approach | What It Stores | When to pick it |
|---|---|---|
| Memento ← this | Full state snapshot (opaque) | Non-reversible ops, encapsulation required, checkpoint/restore |
| Command (undo) | Operation + inverse | Operations are easily reversible (addβsubtract, insertβdelete) |
| Event Sourcing | Sequence of events (replay to rebuild state) | Need full audit trail, time-travel queries, CQRS architecture |
| Prototype (clone) | Shallow/deep copy of the object | Need a copy but don’t require encapsulation of internals |
Problems To Solve
Memento problems test whether you can encapsulate state snapshots, manage undo/redo stacks, handle memory constraints, and understand the boundary between originator and caretaker responsibilities.
| Difficulty | Problem | Key Insight |
|---|---|---|
| Easy | Calculator with Undo Build a calculator that accumulates a result (start at 0). Operations: add(n), subtract(n), multiply(n), divide(n). Support undo() to revert the last N operations. The undo manager must NOT know the calculator’s internal result value — use proper Memento encapsulation (marker interface + private inner class). | Tests basic Memento structure. The calculator creates opaque snapshots of its result field. The caretaker stores them on a stack. Key: the caretaker type is CalcMemento (marker), not the concrete class. Verifies that encapsulation is preserved. |
| Medium | Text Editor with Undo + Redo Extend the basic text editor to support both undo and redo. Rules: undo restores previous state and pushes current state onto redo stack. Redo restores from redo stack and pushes current onto undo stack. Any new edit clears the redo stack (future is invalidated). Limit history to 50 entries. | Tests the two-stack undo/redo pattern. Key insight: new actions invalidate the redo stack (you can’t redo after making a new edit). The bounded history tests eviction policy. This mirrors how real editors (VS Code, Word) implement undo/redo. |
| Medium | Game Save System Build a game with state: player position (x, y), health, inventory (list of items), level number. Support: save to named slots (“quicksave”, “checkpoint_1”), load from any slot, list all saves with metadata (timestamp, level). Mementos must be immutable — changing inventory after save must NOT affect the saved snapshot. | Tests deep copying in mementos (inventory list must be cloned, not shared). Named slots test the caretaker managing multiple mementos by key instead of a single stack. Metadata (timestamp) tests that the caretaker can store metadata alongside the opaque memento without seeing its internals. |
| Hard | Drawing Canvas with Incremental Mementos A canvas has shapes (Circle, Rectangle) with positions and properties. Full snapshots are expensive (10,000 shapes). Implement incremental mementos: store only the delta (what changed since the last snapshot). Undo applies the inverse delta. Support: add shape, move shape, delete shape, change color. Full checkpoint every 10 edits for fast recovery. | Tests the advanced “delta memento” optimization. Instead of storing the full canvas, store (operation, affected shapes, old values). Undo reverses the delta. Full checkpoints every N edits prevent long undo chains. This is how production editors (Photoshop, Figma) handle large state efficiently. Combines Memento with Command pattern ideas. |
- When asked about Memento, the interviewer wants to see: (1) three roles clearly named — Originator (creates/restores), Memento (opaque snapshot), Caretaker (stores/retrieves); (2) encapsulation preserved — private inner class or marker interface; (3) deep copy awareness (mutable fields); (4) memory management strategy (bounded history).
- Stand-out answers mention: JDBC
Savepointas a JDK example, the Memento vs. - Command undo tradeoff, event sourcing as the distributed-systems evolution of Memento, and the undo+redo two-stack pattern.