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:
- Text editors: The famous
Ctrl+Z(Undo). - Graphic editors: Recover previous positions or properties of an element.
- 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;
}
}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})");
}
}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);
}
}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!");
}
}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!"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 savessubtract(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?
- Snapshots: When you need to save snapshots of an object’s state (Video games, Editors).
- Strict encapsulation: When direct access to object fields to save them would violate encapsulation.
- 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.