Behavioral

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.

Category: Behavioral Difficulty: Intermediate Interview: Tier 3 Confused with: Command
01
Section One Β· The Problem

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.

Naive approach — external code reaches into the editor’s internals
// βœ— History manager accesses private fields directly class TextEditor { public String content; // ← exposed! public int cursorPos; // ← exposed! public String fontStyle; // ← exposed! public int fontSize; // ← exposed! } class UndoManager { List<String[]> history = new ArrayList<>(); void save(TextEditor editor) { // Must know ALL internal fields and their order history.add(new String[]{ editor.content, String.valueOf(editor.cursorPos), editor.fontStyle, String.valueOf(editor.fontSize) }); } void undo(TextEditor editor) { String[] state = history.removeLast(); editor.content = state[0]; // ← rebuilds state field by field editor.cursorPos = Integer.parseInt(state[1]); editor.fontStyle = state[2]; editor.fontSize = Integer.parseInt(state[3]); } }

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
Without Memento — undo manager reaches into editor internals
UndoManager knows: content, cursorPos, fontStyle, fontSize... TextEditor public content public cursorPos, font... reaches into ✗ Editor fields all public ✗ UndoManager knows all internals ✗ Add a field → update UndoManager ✗ History can be tampered with ✗ No encapsulation boundary

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.

02
Section Two Β· The Pattern

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.

GoF Intent: “Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.”
— Gamma, Helm, Johnson, Vlissides (1994)
Analogy — saving a video game: In a video game, you press “Save Game.” The game engine (originator) creates a save file (memento) containing your position, health, inventory, quest progress — all internal state. The save file is stored on disk by the OS (caretaker). You can’t open the save file and manually edit your health to 9999 — it’s opaque/encrypted. Later, you press “Load Game” and the game engine restores itself from that save file. The OS never understood what was in the file — it just stored and returned it. The game’s internals were never exposed.

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.

The originator creates a memento via save() — a snapshot of its own state
Only the originator knows what fields to capture. The memento is opaque — no public getters for state fields.
The caretaker stores mementos in a stack/list without inspecting them
The caretaker manages history (push on save, pop on undo) without coupling to the originator’s fields.
On undo, the caretaker passes a memento to originator.restore(memento)
Only the originator can read the memento’s contents and restore itself. Encapsulation preserved.
In Java: memento is a private inner class or record inside the originator
External code can hold a reference to the memento (via a marker interface) but can’t access its fields. Perfect encapsulation.
03
Section Three Β· Anatomy

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.
Memento — UML Class Diagram
TextEditor - content : String - cursorPos : int - fontStyle : String + save() : Snapshot + restore(Snapshot) Snapshot - content : String - cursorPos : int - fontStyle : String (private inner class β€” opaque) UndoManager - history : Stack<Snapshot> + save(editor) + undo(editor) creates stores caretaker calls editor.save() and editor.restore(snapshot) Encapsulation preserved: • Caretaker can’t read Snapshot fields (private inner class of TextEditor) • Only TextEditor creates and restores from Snapshot — no external access to internal state ■ Dark = originator ■ Gold = memento (opaque) ■ Green = caretaker
Memento vs. Command (undo):
  • 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.
04
Section Four Β· How It Works

The Pattern In Motion

Scenario: A text editor. The user types, the caretaker (undo manager) saves snapshots, and Ctrl+Z restores the previous state.

Step 1 — User types “Hello”. Caretaker calls editor.save()
The editor (originator) creates a Snapshot memento containing content="Hello", cursor=5. Returns the opaque snapshot. Caretaker pushes it onto the history stack.
Step 2 — User types “ World”. Caretaker saves again
Editor creates another snapshot: content="Hello World", cursor=11. History stack now has 2 mementos. Caretaker doesn’t look inside them.
Step 3 — User presses Ctrl+Z. Caretaker calls editor.restore(history.pop())
The caretaker pops the top snapshot and passes it to the editor. The editor reads its own private inner class, restores content="Hello", cursor=5. State reverted.
Step 4 — The caretaker never accessed content or cursor directly
Encapsulation preserved. Adding a new field (e.g. selectionRange) to the editor only requires updating the Snapshot inner class — the caretaker is untouched.
Memento — Save/Restore Timeline
save() "Hello" cursor=5 save() "Hello World" cursor=11 save() "Hello World!!!" cursor=14 undo() snapshot 1 snapshot 2 snapshot 3 restores #2
The pattern in pseudocode
// ── Text editor with undo ── TextEditor editor = new TextEditor(); UndoManager undo = new UndoManager(); editor.type("Hello"); undo.save(editor); // snapshot: "Hello" editor.type(" World"); undo.save(editor); // snapshot: "Hello World" editor.type("!!!"); undo.save(editor); // snapshot: "Hello World!!!" System.out.println(editor); // "Hello World!!!" undo.undo(editor); // ← restores from last snapshot System.out.println(editor); // "Hello World" undo.undo(editor); System.out.println(editor); // "Hello"
When to save:
  • 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.
05
Section Five Β· Java Stdlib

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.

IN JAVA
Example 1 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.
Example 2 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.
Example 3 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.
Example 4 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.
Stdlib usage — JDBC Savepoints as Memento
// JDBC Savepoint = database state memento Connection conn = dataSource.getConnection(); conn.setAutoCommit(false); // Save state (create memento) Savepoint sp = conn.setSavepoint("before_update"); // ← memento try { stmt.executeUpdate("UPDATE accounts SET balance = balance - 100 WHERE id = 1"); stmt.executeUpdate("UPDATE accounts SET balance = balance + 100 WHERE id = 2"); conn.commit(); } catch (SQLException e) { conn.rollback(sp); // ← restore from memento β€” undo the partial transfer }
Serialization IS Memento:
  • 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.
06
Section Six Β· Implementation

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.

Java — Memento Pattern Text Editor (core)
// ── Originator: TextEditor ── class TextEditor { private StringBuilder content = new StringBuilder(); private int cursor = 0; // Memento: private inner record β€” opaque to outsiders private record Snapshot(String content, int cursor) implements EditorMemento {} public EditorMemento save() { return new Snapshot(content.toString(), cursor); } public void restore(EditorMemento m) { Snapshot s = (Snapshot) m; content = new StringBuilder(s.content()); cursor = s.cursor(); } } // Marker interface β€” caretaker sees only this (no getters) interface EditorMemento {}
Private inner class for true encapsulation:
  • In Java, the Snapshot record is a private inner class of TextEditor.
  • The caretaker holds references typed as EditorMemento (a marker interface with no methods).
  • It literally cannot access content or cursor.
  • This is the GoF-recommended approach for maximum encapsulation.
07
Section Seven Β· Watch Out

Common Mistakes

Mistake #1 — Storing mementos indefinitely (memory leak): Each memento is a full snapshot of the originator’s state. If you push a memento onto the history stack after every keystroke in a text editor, you’ll quickly consume gigabytes for large documents. Fix: Limit history size (e.g. last 100 snapshots). Use a bounded deque. Or use delta/incremental mementos: store only what changed since the last snapshot (more complex but memory-efficient).
✗ Wrong — unbounded history
// βœ— Unbounded stack β€” will OOM on a 10MB document after 10,000 edits class UndoManager { List<EditorMemento> history = new ArrayList<>(); // grows forever! void save(TextEditor e) { history.add(e.save()); } }
✔ Correct — bounded history
// βœ“ Bounded deque β€” oldest snapshots evicted when capacity exceeded class UndoManager { private static final int MAX_HISTORY = 100; private final Deque<EditorMemento> history = new ArrayDeque<>(); void save(TextEditor e) { if (history.size() >= MAX_HISTORY) history.removeLast(); history.push(e.save()); } }
Mistake #2 — Exposing memento internals (breaking encapsulation):
  • 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.
Mistake #3 — Storing mutable references in the memento:
  • If the originator has a List<String> tags field 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.
Mistake #4 — Conflating Memento with serialization:
  • 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.
Mistake #5 — No redo support:
  • A naive undo stack discards the “undone” memento forever.
  • Users expect redo (Ctrl+Y).
  • Fix: Use two stacks: undoStack and redoStack. 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).
08
Section Eight Β· Decision Guide

When To Use Memento

Use Memento When
  • 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)
Avoid Memento When
  • 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
Memento vs. Alternatives
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
Decision Flowchart
Need to save and restore object state? No Not Memento Yes Operations easily reversible? Yes Command undo (do + inverse) No Encapsulation needed? (hide state from caretaker) No Prototype/Clone (simple state copy) Yes Memento Pattern
09
Section Nine Β· Practice

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.
Interview Tip:
  • 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 Savepoint as 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.