In the Memento design pattern, what problem does it solve, and what are the responsibilities of the originator, the memento, and the caretaker?
answer
- capture + externalize state, keep encapsulation
- originator saves/restores
- memento = opaque immutable snapshot
- caretaker stores, never peeks
- undo stack is the canonical caretaker
basics
~20 sMemento saves a snapshot of an object's internal state so it can be put back later (for example, undo) without exposing that object's internals. The originator makes and restores snapshots, the memento holds the saved state, and the caretaker stores mementos without looking inside them.
solid answer
~50 sMemento is a behavioral pattern. Intent: capture and externalize an object's internal state so the object can be restored to that state later, without violating encapsulation. Three roles collaborate. The originator is the object whose state matters; it exposes something like save(): Memento and restore(m: Memento). The memento is an opaque value object holding a copy of that state; only the originator can meaningfully interpret it. The caretaker (an undo stack, history manager, or transaction scope) asks the originator to save, keeps the mementos in order, and hands one back on undo, but treats them as black boxes and never inspects or mutates them. The win over just making fields public is that state stays private: the originator alone decides what a snapshot contains and how to reapply it, so its internal representation can change without breaking the caretaker.
code
pseudocode · 12 linesclass Editor { // Originator
private text, cursor, selection
save(): Memento = Memento(text, cursor, selection) // only Editor builds it
restore(m: Memento) { text = m.text; cursor = m.cursor; selection = m.selection }
}
class History { // Caretaker — knows nothing about the fields
private stack: Stack<Memento>
backup(e: Editor) { stack.push(e.save()) }
undo(e: Editor) { if (!stack.empty) e.restore(stack.pop()) }
}go deeper
Name the intent (save/restore state without exposing internals) and the three roles with one sentence each; the undo stack example is enough.
Add how opacity is enforced (narrow vs wide interface, nested class, package-private visibility) and note that the originator chooses what to capture.
Discuss memory cost versus history depth, immutability of the snapshot, deep vs shallow copying, and when Command-based undo is the better fit.
Frame it as a general checkpoint/rollback strategy: snapshot cadence, bounded histories, structural sharing, snapshots as an optimization over event replay, and the boundary where external side effects require compensating actions instead.
## The problem it solves You have an object whose state changes over time — a text document, a drawing canvas, a game character, a multi-step form, a configuration — and you want to roll it back to an earlier state. Undo/redo, "Cancel" on a wizard, transaction rollback, checkpoints in a simulation, and snapshot-based crash recovery are all the same shape. The naive approach is to reach into the object from the outside: read every field, stash the values somewhere, and write them back later. That works, but it forces the object to expose its internals (public fields or a full set of getters and setters). Now every other part of the program can also poke at those fields, invariants (rules that must always hold, like "start <= end") can be broken by any caller, and you can never change the internal representation without breaking the code that saves and restores it. Encapsulation — keeping internal representation private and letting the object guard its own rules — is destroyed. **Memento's intent** (from the original Gang of Four catalogue): *without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later*. ## The three roles **1. Originator** — the object that owns the state. It has two extra operations: - `save()` / `createMemento()` → produces a memento containing a copy of whatever it needs to be restorable. - `restore(memento)` → takes a memento it previously produced and reinstates that state. Critically, only the originator decides *what* goes into a snapshot. It may skip caches, derived fields, or transient things (open sockets, UI handles) it can rebuild. **2. Memento** — a plain value object holding the captured state. It is *opaque* to everyone except the originator: no public accessors for the state (or only trivial metadata like a timestamp or label). It should be immutable, so a stored snapshot cannot drift after it is taken. **3. Caretaker** — whoever manages the history: an undo stack, a redo stack, a bounded ring buffer, a transaction manager. Its contract is deliberately dumb: *ask the originator to save, keep the memento, give it back later*. It never reads the contents. This is what keeps the coupling low — the caretaker works for any originator. ## Typical flow 1. Before an operation that mutates the originator, the caretaker calls `originator.save()` and pushes the returned memento on a stack. 2. The operation runs and mutates the originator. 3. On undo, the caretaker pops the memento and calls `originator.restore(memento)`. ## Why the caretaker must stay blind If the caretaker could read the memento's fields, you would have re-created the encapsulation leak by another route: the caretaker would depend on the originator's internal shape, and changing that shape would break the history code. Languages give you different tools for enforcing the opacity — nested/inner classes with private members, package-private or internal visibility, a public *narrow* interface (metadata only) plus a private *wide* interface (the actual state), or a sealed/opaque handle. The intent is the same everywhere: two audiences, two views. ## What Memento is not - It is not a serialization format. Mementos are usually in-memory; serializing them is an implementation choice. - It is not a diff. The classic form stores full snapshots; incremental/delta storage is an optimization you add when snapshots get big. - It is not the only way to do undo. Command (store the operation plus enough information to invert it) is the common alternative, and the two are frequently combined. ## Costs Retaining snapshots costs memory proportional to (size of state) × (history depth). Real systems bound the history, snapshot only at meaningful boundaries, share immutable substructure between snapshots, or store deltas. Restoring also has to be *complete*: if part of the state lives outside the originator (a file on disk, a row in a database, a message already sent), restoring the memento will not undo that, and you need compensating actions.
- Why should the caretaker not be able to read the memento's contents?Because then the caretaker would depend on the originator's internal representation, re-creating the encapsulation leak Memento exists to avoid. Any change to the originator's fields would break the history code, and a caretaker could hand back a tampered snapshot that violates the originator's invariants.
- Does the memento have to contain every field of the originator?No. The originator decides. Derived values, caches, and rebuildable resources (open connections, UI handles) can be omitted and recomputed on restore; only the state needed to reconstitute an equivalent object must be captured.
A hotel safe-deposit box. You (originator) put your valuables in; the front desk (caretaker) stores the box and hands it back on request but has no key and never looks inside. The box (memento) means nothing to anyone but you.
saying these in an interview costs you the question
- Saying Memento requires making the originator's fields public — that is precisely what it avoids.
- Letting the caretaker read or edit the snapshot's state, which reintroduces the coupling.
- Confusing Memento with Prototype: Prototype clones an object to produce another usable object; Memento produces an opaque snapshot used only for restoration.
- Claiming a memento is always a full deep copy — the originator chooses what to include, and deltas or shared immutable structure are valid implementations.
- Assuming restoring a memento undoes side effects outside the originator (files written, emails sent, rows committed).