備忘錄模式在不破壞封裝前提下,捕捉物件內部狀態並外部化儲存,支援後續恢復。常用於 Undo/Redo、交易回滾、棋局悔棋等場景。核心三角色:
GoF 原書以 C++ friend 實現「發起人可見備忘錄細節、管理者僅見窄介面」。Java 無 friend 機制,需替代方案:
MementoIF(窄介面):標記介面,管理者僅持有此型別參考。MementoWideIF(寬介面):含 getState() 等方法,發起人轉型後存取。
public class Originator {
private int state = 90;
private Caretaker caretaker = new Caretaker();
// 發起人對外 API
public void createMemento() { caretaker.saveMemento(new Memento(state)); }
public void setMemento() {
Memento m = (Memento) caretaker.getMemento();
state = m.getState();
}
// 私有內部類:外部完全不可見
private class Memento implements MementoIF {
private final int state;
private Memento(int state) { this.state = state; }
private int getState() { return state; }
}
}
// 窄介面
interface MementoIF {}
// 管理者:只能操作 MementoIF
class Caretaker {
private MementoIF m;
void saveMemento(MementoIF m) { this.m = m; }
MementoIF getMemento() { return m; }
}
優點:Memento 為 private,外部連類別名稱都不可見,徹底封裝。發起人同時扮演 Facade 簡化用戶端呼叫。
讓發起人實作 Cloneable,備忘錄直接用 clone() 複製。缺點:淺拷貝風險、破壞封裝(需公開 clone())、無法精確控制備份範圍。
備忘錄模式的精髓在於「狀態外部化且不破壞封裝」,Java 開發者應優先採用私有內部類方案,兼顧型別安全與封裝純度。