Skip to content

Memento Design Pattern (Behavioral)

Memento is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.


Imagine you’re creating a text editor app. In addition to simple text editing, your editor can format text, insert images, etc. At some point, you decide to let users undo any operations carried out on the text.

To implement this, you might try to make the editor record its state before performing any operation. However, most objects have their data stored in private fields. Even if you make them public, any change to the editor class might break the classes that copy its state. You end up with a choice: either expose all internal details of the editor (breaking encapsulation) or make it impossible to save its state.

The Memento pattern delegates creating the state snapshots to the actual owner of that state, the Originator object. Instead of other objects trying to copy the state from the β€œoutside,” the originator itself produces a special object called a Memento.

The memento is a value object that acts as a snapshot of the originator’s state. It is common practice to make the memento immutable and pass the data only once, via the constructor. Other objects, known as Caretakers, can store these mementos but cannot access or modify the data inside them. When a user triggers an undo, the caretaker gives a memento back to the originator, which uses it to restore its own state.

Think of the Undo feature in a digital camera or a specialized β€œSave State” in a video game. Before a player enters a boss fight, they save the game. The save file (the Memento) contains all the character’s stats and progress. The player (the Caretaker) keeps the file but can’t change the stats inside it. If the character dies, the game (the Originator) reads the save file and restores the character to the exact state they were in before the fight.


  1. Originator: The class that can produce snapshots of its own state and restore its state from snapshots.
  2. Memento: A value object that acts as a snapshot.
  3. Caretaker: Knows β€œwhen” and β€œwhy” to capture the originator’s state, but also β€œwhen” the state should be restored. It keeps a history of mementos.
  4. Encapsulation: In the strict implementation, the memento’s fields are accessible only to the originator that created it.
classDiagram
    class Originator {
        -state: string
        +save() Memento
        +restore(m: Memento)
    }
    class Memento {
        -state: string
        +Memento(state: string)
        +getState() string
    }
    class Caretaker {
        -originator: Originator
        -history: Memento[]
        +undo()
    }

    Originator ..> Memento : creates
    Caretaker o-- Memento : stores
    Caretaker --> Originator : triggers

# The originator holds important state that may change over time.
class Editor:
private field text, curX, curY, selectionWidth
method setText(text):
this.text = text
# Saves the current state inside a memento.
method save():
return new Snapshot(this, text, curX, curY, selectionWidth)
# The memento object stores the past state of the editor.
class Snapshot:
private field editor: Editor
private field text, curX, curY, selectionWidth
constructor Snapshot(editor, text, x, y, width):
this.editor = editor
this.text = text
this.curX = x
this.curY = y
this.selectionWidth = width
# Restores the editor's state.
method restore():
editor.setFields(text, curX, curY, selectionWidth)
# The caretaker keeps track of the snapshots.
class Command:
private field backup: Snapshot
method makeBackup():
backup = editor.save()
method undo():
if (backup != null):
backup.restore()

  • Snapshots: Use the Memento pattern when you want to produce snapshots of the object’s state to be able to restore a previous state.
  • Encapsulation: Use the pattern when direct access to the object’s fields/getters/setters violates its encapsulation.
  1. Determine which class will play the role of the Originator.
  2. Create the Memento class and declare a set of fields that mirror the state declared inside the originator.
  3. Make the memento class immutable.
  4. Add a method for creating mementos to the originator class.
  5. Add a method for restoring the originator’s state to its class.
  6. The Caretaker should know when to ask the originator for a memento and store it in a stack or list.

Pros:

  • You can produce snapshots of an object’s state without violating its encapsulation.
  • You can simplify the originator’s code by letting the caretaker maintain the history of the originator’s state.

Cons:

  • The app might consume lots of RAM if clients create mementos too often.
  • Caretakers must track the originator’s lifecycle to be able to destroy obsolete mementos.
  • Most dynamic programming languages (Python, PHP, JavaScript) can’t guarantee that the state within the memento stays untouched.
  • Command and Memento can be used together when implementing β€œundo”.
  • Memento can be used along with Iterator to capture the current iteration state and roll it back if necessary.
  • Sometimes Memento can be used along with Prototype if the state you want to store in history is simple and doesn’t require links to external resources.

// Memento
public class Memento
{
public string State { get; }
public Memento(string state)
{
State = state;
}
}
// Originator
public class Editor
{
public string Text { get; set; }
public Memento Save() => new Memento(Text);
public void Restore(Memento memento)
{
Text = memento.State;
}
}
// Caretaker
public class History
{
private readonly Stack<Memento> _states = new();
public void Push(Memento m) => _states.Push(m);
public Memento Pop() => _states.Pop();
}
// Usage
class Program
{
static void Main()
{
var editor = new Editor();
var history = new History();
editor.Text = "Version 1";
history.Push(editor.Save());
editor.Text = "Version 2";
history.Push(editor.Save());
editor.Text = "Version 3";
editor.Restore(history.Pop());
Console.WriteLine(editor.Text); // Version 2
editor.Restore(history.Pop());
Console.WriteLine(editor.Text); // Version 1
}
}