patron-memento

Memento Pattern: Save and Restore State

  • 5 min

The Memento is a snapshot of an object’s internal state that can be restored later without exposing the details the object itself encapsulates.

In software, we often need to recover a previous state:

  1. Text editors: The famous Ctrl+Z (Undo).
  2. Graphic editors: Recover previous positions or properties of an element.
  3. Video games: Save a snapshot of the relevant game state.

The problem is: How do we save an object’s state if its variables are private? If we make all variables public to save them to a file, we break Encapsulation. Anyone could modify our character’s health from outside.

The Memento pattern solves this by allowing us to save a “snapshot” of an object’s state, so that only the object itself can read it later.

The 3 Actors

The pattern defines three very clear roles to manage this “safe box”:

Originator: The object whose state we want to save (the Editor, the Character). It knows how to create a Memento with its data and how to restore itself using one.

Memento (The Memory): A sealed box containing the state. It is immutable. Importantly, no one (except the Originator) should be able to see or modify what’s inside.

Caretaker: The one who saves the Mementos (e.g., the History). It knows when to save and when to restore, but does not know what’s inside the Memento and cannot touch it.

:::

Implementation in C#

Let’s implement the undo system of a small Text Editor.

The Memento (The Black Box)

This class stores the state. Notice it is simple and immutable (only get accessors).

public class EditorMemento
{
    // Saved state: Text content, cursor position, etc.
    public string Content { get; }
    public DateTime SaveDate { get; }

    public EditorMemento(string content)
    {
        Content = content;
        SaveDate = DateTime.Now;
    }
}
Copied!

The Originator (The Editor)

This is the main class. It has methods to create the snapshot (Save) and to restore it (Restore).

public class TextEditor
{
    // Internal state (which we want to protect)
    private string _content;

    public void Write(string text)
    {
        _content += text;
        Console.WriteLine($"📝 Editor updated: \"{_content}\"");
    }

    // --- MEMENTO PATTERN METHODS ---

    // Creates a "photo" of the current state
    public EditorMemento Save()
    {
        Console.WriteLine("💾 Saving state...");
        return new EditorMemento(_content);
    }

    // Restores the state from a "photo"
    public void Restore(EditorMemento memento)
    {
        _content = memento.Content;
        Console.WriteLine($"⏪ Restored to: \"{_content}\" (Date: {memento.SaveDate})");
    }
}
Copied!

The Caretaker (The History)

Manages the stack of memories. It is responsible for implementing “Ctrl+Z”.

public class History
{
    // A Stack is ideal for undo (LIFO: Last In, First Out)
    private Stack<EditorMemento> _history = new Stack<EditorMemento>();
    private TextEditor _editor;

    public History(TextEditor editor)
    {
        _editor = editor;
    }

    // Makes a backup
    public void Backup()
    {
        _history.Push(_editor.Save());
    }

    // Undoes the last change
    public void Undo()
    {
        if (_history.Count == 0)
        {
            Console.WriteLine("⚠️ Nothing to undo.");
            return;
        }

        var memento = _history.Pop();
        _editor.Restore(memento);
    }
}
Copied!

Putting it all together

class Program
{
    static void Main(string[] args)
    {
        var editor = new TextEditor();
        var history = new History(editor);

        // 1. Write something
        editor.Write("Hello, ");
        history.Backup(); // Save state 1

        // 2. Write more
        editor.Write("World ");
        history.Backup(); // Save state 2

        // 3. Write an error
        editor.Write("Cruelllll");
        
        // 4. Oops! Undo (Back to "Hello World ")
        history.Undo();

        // 5. Undo again (Back to "Hello, ")
        history.Undo();
        
        // 6. Write the correct text
        editor.Write("friends!");
    }
}
Copied!

Output:

📝 Editor updated: "Hello, "
💾 Saving state...
📝 Editor updated: "Hello, World "
💾 Saving state...
📝 Editor updated: "Hello, World Cruelllll"
⏪ Restored to: "Hello, World " (Date: ...)
⏪ Restored to: "Hello, " (Date: ...)
📝 Editor updated: "Hello, friends!"
Copied!

Memento vs Command

Both patterns can implement “Undo”, but they work in opposite ways:

  • Command: Saves the inverse operation. If you performed add(5), the command saves subtract(5).

  • Advantage: Low memory usage.

  • Disadvantage: Difficult to implement if the operation is not mathematically reversible or depends on complex states.

  • Memento: Saves a copy of the state. It is brute force. It restores the memory exactly as it was.

  • Advantage: Restores any state, however complex, without needing inverse math.

  • Disadvantage: Consumes a lot of RAM. If you save the state of a giant object every time you press a key, you will run out of RAM.

When to use Memento?

  1. Snapshots: When you need to save snapshots of an object’s state (Video games, Editors).
  2. Strict encapsulation: When direct access to object fields to save them would violate encapsulation.
  3. Transactions: When you need to revert to an initial state if a complex operation fails.

Memento allows restoring the past without exposing the object’s internals. It’s important to control memory consumption: saving many large snapshots can be costly.