概要
Memento(メメント)パターンは、
オブジェクトの内部状態を外部に公開することなく、状態のスナップショットを保存・復元できる設計パターンである。
「Undo/Redo機能」や「タイムトラベルデバッグ」、「状態復元」のような操作に最適で、可逆的な操作を可能にする。
1. なぜMementoが必要か?
❌ 現在の状態を上書きするだけでは、過去に戻れない
text.set("新しいテキスト") # 前の状態は消えてしまう
→ 履歴を管理しないと取り消しができない
✅ 状態をMementoとして保存すれば、復元が可能になる
history.append(text.save())
...
text.restore(history.pop())
→ 状態を「保存・復元」できる構造で、安全にUndoが実現
2. 基本構造
✅ Memento(スナップショット)
class Memento:
def __init__(self, state):
self._state = state
def get_state(self):
return self._state
✅ Originator(状態を持つ本体)
class TextEditor:
def __init__(self):
self._content = ""
def write(self, text):
self._content += text
def show(self):
print(self._content)
def save(self):
return Memento(self._content)
def restore(self, memento: Memento):
self._content = memento.get_state()
✅ Caretaker(Mementoの管理者)
class History:
def __init__(self):
self._stack = []
def push(self, memento):
self._stack.append(memento)
def pop(self):
return self._stack.pop() if self._stack else None
✅ 使用例
editor = TextEditor()
history = History()
editor.write("Hello, ")
history.push(editor.save())
editor.write("World!")
editor.show() # Hello, World!
editor.restore(history.pop())
editor.show() # Hello,
3. Python的応用:状態スナップショットをdictで表現する
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
def snapshot(self):
return {"count": self.count}
def restore(self, snap):
self.count = snap["count"]
→ 辞書やJSON形式で状態をスナップショット化することで汎用性が高まる
4. 実務ユースケース
✅ テキストエディタのUndo/Redo
→ 操作前の状態を保存しておき、Undoで復元
✅ グラフィックソフトの履歴機能(Photoshop等)
→ 状態スナップショットによる柔軟なタイムトラベル
✅ テスト中の状態退避(前後比較・巻き戻し)
→ ある処理の開始時点の状態を記録し、復元テストに活用
✅ ゲームにおけるセーブポイントや巻き戻し機能
→ ゲーム進行の断面を保存・復元するメカニズム
5. よくある誤用と対策
❌ Mementoが状態を丸ごと持ちすぎて重い
→ ✅ 最小限の差分・変更のみをスナップショットにする
❌ OriginatorがMementoの内部構造を操作してしまう
→ ✅ Mementoは読み取り専用とし、カプセル化を守る
❌ Mementoの履歴が膨張しメモリを圧迫
→ ✅ 保存上限・差分保存・圧縮などの最適化が必要
結語
Mementoパターンとは、“過去の状態を封じ込め、未来で取り出せる設計”である。
- 状態の保存と復元を構造化し、安全なUndo/Redoを実現
- 内部情報をカプセル化したまま、タイムトラベルを可能にする
- Pythonではオブジェクトや辞書・JSONなどで、柔軟に表現可能
Pythonicとは、“変化を記録し、巻き戻し可能にする知性”。
Mementoパターンはその知性を、記憶という構造で静かに包む技法である。