In real applications, requirements such as Undo / Redo, change history, reverting to a previous state or state snapshots frequently appear.
The problem arises when we want to save the state of an object without exposing its internal structure.
This is where the Memento Pattern comes in, a behavioral design pattern that helps us to:
-
save the state of an object,
-
restore that state later,
-
without violating the encapsulation principle.
The problem solved by the Memento Pattern
Let's assume we have a complex object (e.g., document, form, text editor):
-
it has many internal properties;
-
its state changes frequently;
-
we need undo / redo.
❌ Wrong solutions:
-
exposing internal properties;
-
copying the entire object;
-
undo logic scattered all over the code.
✅ The correct solution:
The object creates its own "snapshot" of the state → Memento.
Pattern structure
The Memento Pattern involves three clear roles:
1️⃣ Originator
-
the object whose state needs to be saved;
-
creates and restores mementos.
2️⃣ Memento
-
contains the internal state;
-
is opaque to the rest of the application.
3️⃣ Caretaker
-
manages the list of mementos;
-
does not know the content of these.
Conceptual diagram (simplified)
Caretaker ---> Memento <--- Originator
^
|
creates / restores
Practical example in C# – Undo for a document
🎯 Scenario
We have a document editor that:
-
modifies text;
-
allows undo.
1️⃣ Memento – the state snapshot
public class DocumentMemento
{
public string Content { get; }
public DocumentMemento(string content)
{
Content = content;
}
}
🔒 Note:
Memento only stores the state, it contains no logic.
2️⃣ Originator – the main object
public class Document
{
public string Content { get; private set; } = string.Empty;
public void Write(string text)
{
Content += text;
}
public DocumentMemento Save()
{
return new DocumentMemento(Content);
}
public void Restore(DocumentMemento memento)
{
Content = memento.Content;
}
}
📌 The document:
-
creates its own snapshot;
-
knows how to restore its state.
3️⃣ Caretaker – the undo manager
public class DocumentHistory
{
private readonly Stack<DocumentMemento> _history = new();
public void Save(DocumentMemento memento)
{
_history.Push(memento);
}
public DocumentMemento? Undo()
{
return _history.Count > 0 ? _history.Pop() : null;
}
}
🔐 The Caretaker:
-
does not know what the memento contains;
-
only stores and returns it.
4️⃣ Usage
var document = new Document();
var history = new DocumentHistory();
document.Write("Hello ");
history.Save(document.Save());
document.Write("World!");
history.Save(document.Save());
Console.WriteLine(document.Content); // Hello World!
var previousState = history.Undo();
if (previousState != null)
{
document.Restore(previousState);
}
Console.WriteLine(document.Content); // Hello
Benefits
✅ Maintains encapsulation
✅ Clean code for undo/redo
✅ Clear separation of responsibilities
✅ Easy to extend (multi-level undo, redo stack)
Disadvantages
⚠️ Memory consumption (many snapshots)
⚠️ Requires attention with very large objects
⚠️ Can become costly without history limits
When to use the Memento Pattern
✔ Undo / Redo
✔ Change history
✔ State snapshots
✔ Editors, forms, configurations
✔ Desktop, web, enterprise applications
❌ Avoid if:
-
the state is trivial;
-
you don't need restoration;
-
objects are very large and moved frequently.
Memento Pattern vs other patterns
|
Pattern |
Purpose |
|---|---|
|
Memento |
Saving state |
|
Command |
Undo by reversing actions |
|
Prototype |
Object copying |
|
State |
Behavior depending on state |
📌 Memento ≠ Command, but they are often used together.
Conclusion
The Memento Pattern is the elegant solution for state management without architectural compromises.
It is indispensable when you want undo/redo functionality without turning your code into a hard-to-maintain "monster".