Skip to content
FollowtheDamnCode

Memento

Capture an object's state as an opaque snapshot so it can be restored later — without exposing its insides.

Big idea

A Memento is a snapshot of an object's internal state, created by the object itself and handed to someone else to keep. The keeper (a history, a save slot) can store and return snapshots but can't look inside or change them — so you get undo, checkpoints, and rollbacks without breaking encapsulation.

The problem it solves

A drawing app needs undo. The easy way: let the history class read every field of the canvas — shapes, layers, selection, zoom — and copy them. Now the history depends on the canvas's private layout; add a field and undo silently stops restoring it. Make the fields public to allow the copying, and every other class can now poke at them too.

Think of it like

A game's save point. The game writes your entire state into a save file; the console's storage keeps the file but has no idea what's in it. When you load, the game reads its own file back. The storage didn't need to understand inventories or health bars — it just kept the box safe.

Structure

The originator makes and reads mementos; the caretaker only keeps them
  • Originator (Character) — creates snapshots of itself and restores from them.
  • Memento (Snapshot) — immutable; its contents are meaningful only to the originator.
  • Caretaker (Checkpoints) — decides when to save and restore, never what.

In code

Checkpoints that know nothing about characters
import copy

class Snapshot:
    def __init__(self, label, state):
        self.label = label
        self._state = state                  # opaque to everyone but the originator


class Character:
    def __init__(self):
        self._hp, self._x, self._inventory = 100, 0, ["torch"]

    def act(self, move, damage=0, item=None):
        self._x += move
        self._hp -= damage
        if item:
            self._inventory.append(item)

    def save(self, label):
        return Snapshot(label, copy.deepcopy((self._hp, self._x, self._inventory)))

    def restore(self, snapshot):
        self._hp, self._x, self._inventory = copy.deepcopy(snapshot._state)

    def __str__(self):
        return f"hp={self._hp} x={self._x} items={self._inventory}"


class Checkpoints:                           # the caretaker
    def __init__(self):
        self._stack = []
    def push(self, snapshot):
        self._stack.append(snapshot)
    def pop(self):
        return self._stack.pop()


hero, saves = Character(), Checkpoints()
saves.push(hero.save("start"))
hero.act(5, item="key")
saves.push(hero.save("found key"))
hero.act(3, damage=80, item="cursed ring")
print("now:     ", hero)
snap = saves.pop()
hero.restore(snap)
print("restored:", hero, f"({snap.label})")
hero.act(-2)
hero.restore(saves.pop())
print("restored:", hero)
output
now:      hp=20 x=8 items=['torch', 'key', 'cursed ring']
restored: hp=100 x=5 items=['torch', 'key'] (found key)
restored: hp=100 x=0 items=['torch']

Run and edit it in the app.

The deep copy matters: without it, the snapshot would share the inventory list with the live character, and picking up the cursed ring would also "change the past".

Who should be able to read a memento's contents?

Watch it

Memento or Command for undo?

  • Memento — snapshot the whole state before each change; undo restores it. Simple and robust, but memory-heavy for large state.
  • Command — each action knows how to reverse itself. Light on memory, but every command needs a correct inverse.
  • Many editors combine them: commands that store a small memento of only what they change.

When to use it — and when not to

Use it for undo, checkpoints and rollbacks (games, wizards, transactions), and "cancel" on edit dialogs. Beware with large or frequently changing state — snapshots can eat memory fast; consider storing diffs, limiting history depth, or using commands instead.

Pros and cons

ProsCons
Undo and rollback without exposing internalsSnapshots can use a lot of memory
Caretaker stays simple and genericDeep vs shallow copy bugs (see Prototype)
Originator controls exactly what is savedCaretakers must prune old snapshots

How it relates

  • Command is the other undo mechanism; they're often used together.
  • Prototype also copies state, but to create a new object rather than restore an old one.
  • Iterator state can be captured as a memento to resume traversal later.
  • At system scale, database snapshots and event sourcing play the same role.

An image editor stores a full memento of a 50 MB image after every brush stroke. What's the most likely problem?

Key terms

  • Memento — An opaque snapshot of an object's state that can be restored later.
  • Originator — The object that creates mementos of itself and restores from them.
  • Caretaker — The object that stores mementos and decides when to save or restore, without reading them.
  • Checkpoint — A saved state you can roll back to.