備忘錄模式屬於行為型模式,核心意圖是在不暴露對象內部結構的前提下,捕獲並外部化對象的內部狀態,以便日後恢復。就像文本編輯器的「撤銷」功能,或是資料庫事務的回滾機制,都是備忘錄模式的典型應用場景。
class Originator {
private String state;
public String getState() { return state; }
public void setState(String state) { this.state = state; }
public Memento createMemento() { return new Memento(state); }
public void restoreMemento(Memento m) { state = m.getState(); }
}
class Memento {
private final String state;
public Memento(String state) { this.state = state; }
public String getState() { return state; }
}
class Caretaker {
private Memento memento;
public Memento getMemento() { return memento; }
public void setMemento(Memento m) { memento = m; }
}
客戶端先保存狀態,修改後可隨時恢復,邏輯清晰簡潔。
實際開發中,發起人往往是包含多個屬性的 JavaBean,且需要多個歷史版本。採用 Map<String, Object> 存儲屬性名值對,結合 Introspector 實現屬性的通用備份與恢復:
class Originator {
private String state1, state2, state3;
// getter/setter 省略
public Memento createMemento() {
return new Memento(BeanUtils.backupProp(this));
}
public void restoreMemento(Memento m) {
BeanUtils.restoreProp(this, m.getStateMap());
}
}
class Memento {
private Map<String, Object> stateMap;
// constructor, getter/setter
}
class BeanUtils {
public static Map<String, Object> backupProp(Object bean) { ... }
public static void restoreProp(Object bean, Map<String, Object> map) { ... }
}
class Caretaker {
private Map<String, Memento> memMap = new HashMap<>();
public Memento getMemento(String key) { return memMap.get(key); }
public void setMemento(String key, Memento m) { memMap.put(key, m); }
}
此方案支援任意屬性數量與多版本管理,擴展性極強。
| 優點 | 缺點 |
|---|---|
| 提供狀態回滾能力,容錯性強 | 多狀態多備份時記憶體佔用大 |
| 封裝性好,發起人無需管理備份細節 | 頻繁創建備忘錄可能影響性能 |
適用場景:文本編輯器撤銷/重做、資料庫事務回滾、棋類遊戲悔棋、表單多步驟導航等需要歷史狀態管理的場景。
備忘錄模式以「以空間換時間、以封裝換安全」的思想,優雅地解決了狀態捕獲與恢復的難題。實際應用時需權衡狀態大小與備份頻率,必要時可結合原型模式或序列化優化性能。