0 XP · 0 scenes

Memento

Save a snapshot of an object so you can restore it later
The problem

To support undo you let outside code copy the editor's private fields and write them back.

The idea

The editor itself creates a small memento holding its state, and can restore from one.

Reach for it when

You need undo or save points

1

The picture from life

A save point in a video game. Before the boss fight you save; if you lose, you reload and everything (health, items, position) is exactly as it was. The save file is just a sealed envelope: the game can read it, the player does not edit its insides.

2

The problem

What goes wrong when you do not use it.

To support undo you let outside code copy the editor's private fields and write them back. Now every caller knows the editor's internals, and any change to those fields breaks all of them.

✗ Before
Clientsaved = (editor._text, editor._cursor)editor._text, editor._cursor = savedEditor_text_cursorpokes inside
  • calls / uses
Outside code copies the editor's private fields and writes them back. It must know every detail, and can break the editor.
Reach for it when
  • You need undo or save points
  • You must not expose internals to take a snapshot
  • Transactions that may roll back
3

The idea

How the pattern fixes it.

The editor itself creates a small memento holding its state, and can restore from one. A history object keeps the mementos in a stack but never looks inside them.

✓ After
Editortextsave()restore(memento)Mementotext ← sealedHistorystackpush(memento)pop()save()keeps
  • has a / holds
  • creates
The editor makes a sealed snapshot. The history only stores it and never looks inside.

Who is who

Editor (originator)
Has the state. save() makes a memento, restore(m) loads one.
Memento
An immutable snapshot of the state.
History (caretaker)
Keeps mementos in a stack; never opens them.

Build it in steps

  1. 1Decide what state must be saved.
  2. 2Let the originator build an immutable memento.
  3. 3Keep mementos in a history stack.
  4. 4On undo, pop and restore.
4

Watch it run

Step through the calls. Tap an arrow to jump to it.

ClientEditorMementoHistory1save()2Memento('Hello')3push(memento)4text += ' World'5pop()6restore(memento)
Step 1/6

The text is 'Hello'. Ask the editor for a snapshot.

save()
5

The code

Python and Java. Try writing the classes yourself from the diagram first.

class Memento:
    def __init__(self, text):
        self._text = text                       # sealed: only the editor reads this

    def text(self):
        return self._text


class Editor:
    def __init__(self):
        self.text = ""

    def save(self):
        return Memento(self.text)

    def restore(self, memento):
        self.text = memento.text()


class History:
    def __init__(self):
        self.stack = []

    def push(self, memento):
        self.stack.append(memento)

    def pop(self):
        return self.stack.pop()


def demo():
    editor, history = Editor(), History()
    editor.text = "Hello"
    history.push(editor.save())
    editor.text += " World"
    typed = editor.text
    editor.restore(history.pop())
    return typed, editor.text

What you gain

  • Undo without breaking encapsulation
  • The history stays simple

What it costs

  • Many or big snapshots eat memory
  • For tiny changes, storing diffs (Command) is lighter

You have already met it in

  • Editor undo, browser form restore
  • Database savepoints and snapshots
  • Git commits as snapshots of a tree

Often mixed up with

  • CommandCommand undoes by running the reverse action; Memento undoes by putting back a saved copy.
  • PrototypePrototype clones to make a new working object; Memento stores a frozen state for later.
6

Make it stick

Build a drawing canvas that saves a snapshot before every stroke and supports multi-level undo.

Confidence