Memento Pattern
The Memento is a behavioral design pattern that allows capturing and restoring an object's internal state without exposing its implementation details. It enables undo/redo operations by storing snapshots (mementos) of the object's state externally.
Key Principles
- Encapsulation: Memento stores state privately; only originator can access it.
- Snapshot: Memento is immutable (read-only outside originator).
- Caretaker: Manages mementos (e.g., undo stack); doesn't inspect contents.
- Originator: Creates and restores from mementos.
Structure
- Originator: Object whose state we save/restore.
- Memento: Stores snapshot of originator's state (private access).
- Caretaker: Holds mementos (e.g., history stack).
Python Example: Text Editor with Undo
from typing import List
from datetime import datetime
# Memento (stores state)
class EditorMemento:
def __init__(self, content: str, timestamp: datetime):
self._content = content # Private state
self._timestamp = timestamp
def get_content(self) -> str:
return self._content
def get_timestamp(self) -> datetime:
return self._timestamp
# Originator (creates/restores mementos)
class TextEditor:
def __init__(self):
self._content = ""
def type(self, text: str):
self._content += text
print(f"Current text: {self._content}")
def save(self) -> EditorMemento:
print("Saving state...")
return EditorMemento(self._content, datetime.now())
def restore(self, memento: EditorMemento):
self._content = memento.get_content()
print(f"Restored to: {self._content} (from {memento.get_timestamp()})")
# Caretaker (manages mementos)
class History:
def __init__(self):
self._mementos: List[EditorMemento] = []
def push(self, memento: EditorMemento):
self._mementos.append(memento)
def pop(self) -> EditorMemento:
if self._mementos:
return self._mementos.pop()
raise IndexError("No saved states")
# Usage (Client Code)
if __name__ == "__main__":
editor = TextEditor()
history = History()
editor.type("Hello ")
history.push(editor.save())
editor.type("World!")
history.push(editor.save())
editor.type(" This will be undone.")
print("\nUndoing last change...")
editor.restore(history.pop())
print("\nUndoing another...")
editor.restore(history.pop())
Output:
Current text: Hello
Saving state...
Current text: Hello World!
Saving state...
Current text: Hello World! This will be undone.
Undoing last change...
Restored to: Hello World! (from 2025-... )
Undoing another...
Restored to: Hello (from 2025-... )
When to Use Memento
- Undo/Redo: Editors, games, transactions.
- Checkpointing: Save game states.
- History Tracking: Versioned editing.
- Avoid: Simple state or when immutability suffices.
Summary: Memento captures and externalizes an object's state in immutable snapshots, allowing restoration (e.g., undo) while preserving encapsulation.