Memento Pattern

Save an object's state in a sealed snapshot that only the object itself can read back, so undo and rollback do not expose its internals.

Overview

The problem: undo without opening the box

A text editor needs undo. Somewhere, the state before each edit must be kept: the text, the cursor position, the selection. The undo code (a history list) needs to save and restore that state, but the editor should not have to expose its fields to do it. The moment the history can read and write the editor's internals, every other class can too.

  • Public getters and setters for every field — Yes — No, anyone can now set the cursor past the end — Invariants leak
  • The history keeps a deep copy of the whole editor — Yes — Yes, but copies the undo history too if that lives inside — Wasteful, and easy to get wrong
  • A sealed snapshot the editor creates and reads back — Yes — Yes — One small class

The third row is the Memento pattern.

The pattern

Memento is one of the 23 patterns in the 1994 Gang of Four book (Gamma, Helm, Johnson and Vlissides). Three roles take part. The originator is the object whose state matters; it can produce a snapshot and later accept one back. The memento is that snapshot: a small object that holds state and offers no way for anyone but the originator to read it. The caretaker keeps mementos, in a stack or a list, and hands them back on request. It never looks inside.

A runnable example

The memento is a frozen dataclass: once made, assigning to its fields raises FrozenInstanceError. Python has no private members, so the double-underscore prefix is a signal to readers and a name-mangling step, not a lock. The caretaker keeps a stack and never reads a field.

Undo restores both the text and the cursor in one step, because they were captured together. That is the practical reason a snapshot beats a list of individual field values: the state is always consistent.

Keeping the memento sealed

How much the language helps depends on the language.

  • Java — Make the memento a nested class of the originator with private fields. The language specification allows access to a private member only within the body of the top-level class that encloses its declaration, so the originator can read the memento's fields and no outside class can; the nested class itself can also be declared private
  • C++ — Declare the originator a friend of the memento class
  • Python — Convention only: the tutorial says private instance variables do not exist; a leading underscore marks a non-public name, and __name is mangled to _Class__name

The Gang of Four describe this as two interfaces on one object: a wide one for the originator, a narrow one for everyone else. Only some languages can enforce the narrow one; in the rest, you enforce it in code review.

Snapshots and shared references

A memento must not share mutable objects with the live originator. If the editor's state were a list and the snapshot kept a reference to that same list, later edits would change the snapshot too, and undo would restore the current state. Python's copy docs put the difference this way: a shallow copy inserts references to the original's members, a deep copy inserts copies of them, recursively.

Memento or Command for undo

Both patterns implement undo. Memento stores the state before; Command stores the action and how to reverse it.

  • Undo works for — Any action, with no per-action code — Only actions with a written undo
  • Memory per step — The size of the state — The size of the change
  • Correctness risk — Low: restore is a copy — Each inverse can be wrong
  • Good for — Small state, many action types — Large state, few action types

A rough size check makes the choice concrete. A 200 KB document with 500 edits kept as full snapshots is 200 × 500 = 100,000 KB, about 100 MB. The same 500 edits kept as inverse commands of about 50 bytes each is 500 × 50 = 25,000 bytes, about 25 KB. When the state is large, mix them: a snapshot every N steps, commands in between.

What you will be able to do

  • Explain why undo tempts you to break encapsulation, and how a memento avoids it.
  • Name the three roles and say what the caretaker is never allowed to do.
  • Write a snapshot-based undo with an immutable memento and a stack.
  • Say what your language can enforce about the memento's privacy, and what it cannot.
  • Choose between Memento and Command for a given state size, with the arithmetic.

Interview questions

  • Show the smell Memento fixes, and the fix.
  • Mementos are eating memory. What are your options?
  • How do you add redo?
  • What breaks a memento, and how do you guard against it?

Sign up free to read the full topic

More Low-Level Design topics

Start free on Cariara · Coding problems · System design studio