在不破壞封裝的前提下,擷取並對外保存一個物件的內部狀態,之後可以把它還原回去。負責保管的人(caretaker)只持有快照、不去看裡面的內容。
🧠 When to Use
TIP
訊號:你想做「存檔/回復」或 undo,但又不想把物件的私有欄位全都開成 public 讓外面亂存亂取。
- 需要對物件的內部狀態拍快照,之後能回滾(undo、檢查點、交易回復)。
- 直接暴露狀態會破壞封裝,所以要一個「只能存、不能窺」的中介物。
- 狀態變更步驟多,想保留歷史以便往回走。
⚖️ Structure & Variants
經典版 — Originator 自己產生/吃回快照
class Editor(var text: String = "") {
fun save(): Memento = Memento(text) // 只有 Editor 看得懂內容
fun restore(m: Memento) { text = m.state }
class Memento(val state: String) // 對外不透明的快照
}
val ed = Editor("hello")
val snap = ed.save() // caretaker 拿著 snap,但不解讀它
ed.text = "world"
ed.restore(snap) // 回到 "hello"Memento的內容只有Editor該理解;caretaker 只負責保管與遞回。
搭 Command 做 undo 堆疊
- 每個 Command 執行前先向 originator 取一個 memento 壓進堆疊。
- undo 時彈出最上面的 memento 還原;這是文字編輯器、繪圖工具最常見的組合。
封裝的取捨 — 寬介面 vs 窄介面
- 對 originator 提供寬介面(能讀寫快照全部欄位);對 caretaker 只露窄介面(拿得到、傳得回,看不到內容)。
- 巢狀類別、
internal/friend 機制都是用來維持「只有 originator 看得懂 memento」的手段。
⚠️ Misuse & Anti-patterns
- caretaker 偷看/竄改快照:一旦外面開始解讀 memento 欄位,封裝就破了,等於把私有狀態洩漏出去。
- 快照太大又存太多:每步都深拷貝整個大物件,記憶體爆掉;考慮增量快照或限制歷史長度。
- 拿 memento 當公開 DTO 用:它的用途是「給原物件還原自己」,被別處當資料載體傳來傳去就走味了。
🔑 Takeaways
- 本質是「對外存快照、不破壞封裝」,caretaker 只保管不窺探。
- 和 Command 搭配是做 undo/redo 的標準組合。
- 注意快照大小與歷史長度,別讓「能回到任一步」變成記憶體黑洞。
No notes yet — jot your takeaways or Q&A here.