Free Interactive Course · Design Patterns

Memento Design Pattern

Capture an object's state so it can be restored later — without letting anyone outside the object see what's inside the snapshot.

Behavioural Patternsmediuma.k.a. Tokena.k.a. Snapshot
ShareXLinkedIn
In one sentence

Without violating encapsulation, capture and externalise an object's internal state so that the object can be restored to this state later.

01

The problem Memento solves

The problem

A diagram editor. The user selects forty shapes, drags them, then hits align left and distribute vertically. Each of those touches the position, and often the size, of every selected shape. Then they press Ctrl-Z.

Reversing that by inverse operation means AlignLeftCommand remembering forty original x-coordinates, DistributeCommand remembering forty y-coordinates, and both being careful about what the drag did in between. It's doable, and it's forty chances to be wrong. Some operations have no clean inverse at all — a "tidy up connectors" command that reroutes lines has no formula that puts them back.

The obvious fix is to save the whole canvas before each operation. But now the undo stack — which is UI code — is holding the editor's internal state: the shape list, the z-order table, the connector routing cache, the selection. Every internal field the canvas has is exposed to a class that has no business knowing about it, and refactoring the canvas means changing the undo stack.

02

How the Memento pattern works

Let the object snapshot itself, and hand out a sealed box that only it can open:

  1. The originator (the canvas) has a method that returns a memento — an object holding a copy of its internal state.
  2. The memento's contents are opaque to everyone else. The undo stack can hold it and hand it back, but cannot read or edit a single field.
  3. The caretaker (the undo stack) stores mementos in order. It knows nothing about shapes, z-order or routing caches — only "here is a token from earlier".
  4. To undo, the caretaker gives a memento back to the originator, which restores itself from it. Restoring is one operation regardless of how much changed.
The encapsulation is the pattern — not the snapshotting. Anyone can save a copy of an object's fields; the reason this has a name is that the copy is stored by a class that must not be able to look inside it. Languages express that differently: Java and C# use a private nested class, C++ uses friend, and Python and JavaScript rely on convention because they can't enforce it at all. If your "memento" is a public struct with public fields that the caretaker reads and edits, you've written a snapshot — useful, but you've given up the thing the pattern was protecting.
Canvasthe originatorsave() · restore(m)Mementoopaque to everyoneexcept the Canvasshapes, z-order…UndoStackthe caretakerholds · never openscreatesstoreshands it back on undo — still unopenedthe dashed box is the whole idea: stored by one class, readable only by another
Participants. The Originator creates and consumes mementos. The Memento holds the state and exposes a wide interface to the originator and a narrow one — usually none — to everyone else. The Caretaker keeps mementos in order and never inspects them, which is exactly why it doesn't have to change when the originator's fields do.
03

See it: undo without an inverse

Step through an editing session. Before each operation the canvas saves a memento; undo hands one back and the canvas restores itself wholesale. Notice that undoing a forty-shape align costs exactly the same as undoing a single nudge.

▶ Try it — snapshot, edit, restore

An interactive undo stack built from snapshots: each edit to the canvas is preceded by a memento capturing the whole state, and undo restores a snapshot wholesale rather than computing an inverse operation — so undoing a forty-shape alignment is one restore.

Step four is the argument for this pattern over Command-style undo. "Tidy up connectors" reroutes eighteen lines by an algorithm with no inverse — you cannot compute your way back, you can only remember where they were. And notice what the UndoStack did with all five mementos: held them in order and handed one back. It never learned what a z-order table is.
04

Memento pattern code examples

An opaque snapshot the caretaker can hold but not open — and the deep-copy trap in every language.

public final class Canvas {

    private List<Shape> shapes = new ArrayList<>();
    private Map<ShapeId, Integer> zOrder = new HashMap<>();

    /** The memento. Private constructor and private fields: only Canvas can
     *  read it, which is the entire point of the pattern. */
    public static final class Memento {
        private final List<Shape> shapes;
        private final Map<ShapeId, Integer> zOrder;

        private Memento(List<Shape> shapes, Map<ShapeId, Integer> zOrder) {
            this.shapes = shapes;
            this.zOrder = zOrder;
        }
    }

    public Memento save() {
        // DEEP copy. `new ArrayList<>(shapes)` copies the list but shares the
        // Shape objects — mutate one afterwards and your "snapshot" changes too.
        return new Memento(
                shapes.stream().map(Shape::copy).toList(),
                Map.copyOf(zOrder));
    }

    public void restore(Memento m) {
        this.shapes = new ArrayList<>(m.shapes);
        this.zOrder = new HashMap<>(m.zOrder);
    }
}

/** The caretaker holds mementos and cannot see inside a single one. */
public final class UndoStack {
    private final Deque<Canvas.Memento> stack = new ArrayDeque<>();

    public void record(Canvas canvas) { stack.push(canvas.save()); }

    public void undo(Canvas canvas) {
        if (!stack.isEmpty()) canvas.restore(stack.pop());
    }
}

// Serialization is NOT a substitute: it exposes the fields to anything that can
// read the stream, which gives away the encapsulation you came for.
Read across the tabs: two themes run through all seven. The first is how opacity is enforced — C++ says friend, Java and C# use a nested type with private construction, Go uses package boundaries, TypeScript can fake it with a branded opaque type, and Python relies on an underscore and good manners. The second is the deep-copy trap, and it catches people in every language: a shallow copy of a list shares the objects inside it, so the "snapshot" changes when the original does. The best answer, visible in the C# and TypeScript tabs, is to make the state immutable — then a memento costs a reference copy and the whole problem disappears.
05

How to implement Memento

  1. Give the originator save() and restore(). Nobody else should assemble or interpret a snapshot.
  2. Make the memento opaque with whatever your language offers: a private nested class, friend, package scoping, or a branded token type.
  3. Copy deeply, or make the state immutable so you don't have to. A shallow copy that shares mutable objects is the classic silent failure.
  4. Prefer immutable state and structural sharing for anything large — snapshots then cost a pointer instead of a document.
  5. Bound the history. An unlimited undo stack over big snapshots is a memory leak with a friendly name; cap it, or store deltas and snapshot every N steps.
  6. Keep external resources out: open files, sockets and database handles cannot be restored by assignment. Snapshot the data, re-acquire the resource.
  7. Restore atomically — a half-restored object is worse than no undo at all.
06

When to use Memento — and when not to

Use it when you need a snapshot of an object's state to restore later, and exposing that state directly would break encapsulation. It's the right choice when operations have no clean inverse, when one operation touches a lot of state, or when you want checkpoints — undo, transactions with rollback, wizard back buttons, game saves.

Where it goes wrong

The shallow copy. The snapshot holds the same object references as the live state, so editing a shape afterwards rewrites history. It looks like it works — undo runs without error and simply restores the current values.

Memory. Fifty snapshots of a large document is fifty documents. Cap the history, store deltas with periodic full snapshots, or move to immutable structures that share what didn't change.

A memento that isn't opaque. A public struct the caretaker reads and edits is a snapshot, not a memento — you've kept the copying and thrown away the encapsulation, and now the undo stack breaks when the originator gains a field.

External resources in the state. Restoring an object that holds an open socket or file handle restores a reference to something that has since closed. Snapshot the data, not the connection.

Snapshots taken at the wrong moment. Save before the operation, not after, and take exactly one per user-visible action — otherwise Ctrl-Z undoes half a drag.

You want to…UseBecause
Restore an object's whole prior stateMementoSnapshot and restore, with the internals kept private.
Reverse a specific operation you performedCommandCommand applies an inverse; Memento restores a state. Commonly combined.
Copy an object to create a new onePrototypePrototype produces a usable object; a memento is an opaque token.
Keep a history of edits as a sequence of eventsCommandEvent sourcing stores the commands; snapshots are the optimisation on top.
Iterate a collection that may change underneath youIteratorA robust iterator may snapshot the collection — Memento in a supporting role.
07

Quick check

🧠 Quick check
Your save() returns new ArrayList<>(shapes). Users report that undo "does nothing". Why?

In the wild

C#System.Transactions rollback, and immutable collections making Save() an O(1) reference copy rather than a document copy.
JavaScriptRedux time-travel debugging — the store keeps previous states, and immutable reducer updates give structural sharing for free.
Pythoncopy.deepcopy and the pickling hooks __getstate__/__setstate__, which are the memento interface under another name.
JavaDatabase savepoints through JDBC (Connection.setSavepoint) — a token you hold and hand back, whose contents belong entirely to the database.
C++Qt's QUndoCommand subclasses storing prior state, and the friend idiom that lets exactly one class read the snapshot.
GoPersistent-structure libraries and value-copy snapshots; maps.Clone and slices.Clone exist precisely because the shallow copy is the default.

Frequently asked questions

What is the difference between the Memento and Command patterns for undo?
Command undoes by applying an inverse: it remembers just enough to reverse what it did — the deleted text, the previous value. That's memory-efficient and exact when the operation is small and reversible. Memento undoes by restoring a snapshot of the whole state, which costs more memory but works when an operation touches a great deal of state or has no inverse at all (a re-layout, a reroute, a solver). Real editors use both: commands for small edits, a memento inside the command for big ones.
How is Memento different from just copying an object?
The copying is the easy part; the encapsulation is the pattern. A memento is stored by a caretaker — an undo stack, a history list — that must be able to hold it and hand it back without being able to read or modify it. That's what keeps the caretaker from depending on the originator's internals, so adding a field to the originator doesn't ripple into the undo system. If your snapshot is a public object the caretaker reads, you have a copy with extra steps.
How do you keep Memento from using too much memory?
Four levers, roughly in order of payoff. Make the state immutable so snapshots share everything unchanged — this turns a copy into a pointer and is by far the biggest win. Store deltas with a full snapshot every N steps, the approach databases and version-control systems use. Cap the history at a fixed depth. And snapshot only what can actually change — derived caches can be recomputed rather than stored.
Why does my undo appear to do nothing?
Almost always a shallow copy. Copying the collection but not the objects inside it means the snapshot and the live state share the same instances, so every later mutation edits the snapshot too — undo restores values that are already current, and nothing visibly happens. Deep-copy the elements, or make them immutable. The second most common cause is snapshotting after the operation instead of before it.
Can I use serialization to implement Memento?
You can, and it's a reasonable engine for the copy — especially when the snapshot has to outlive the process, as in a game save. Just be aware of what you're trading: a serialised form is readable by anything that can read the bytes, so the encapsulation the pattern protects is gone, and the format becomes something you have to version. Also watch for the usual serialisation losses — JSON.parse(JSON.stringify(x)) silently destroys Map, Set, Date and cycles, which is why structuredClone exists.

Finish the handbook, earn the certificate

All 23 Gang-of-Four patterns, each with a simulator you can click and code in seven languages. Free, no signup.

See all 23 patterns →
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.