備忘錄模式屬於行為型模式,核心目的是「在不破壞封裝性前提下,捕捉並外部化物件內部狀態,以便日後恢復」。常見應用包括編輯器的復原、資料庫交易回滾、棋類遊戲悔棋等。本文從定義、角色、通用實作、多狀態多備份進階版,到優缺點與適用場景一次講透。
class Originator {
private String state;
public Memento createMemento() { return new Memento(state); }
public void restoreMemento(Memento m) { state = m.getState(); }
// getter/setter 略
}
class Memento {
private final String state;
public Memento(String s) { state = s; }
public String getState() { return state; }
}
class Caretaker {
private Memento memento;
public void setMemento(Memento m) { memento = m; }
public Memento getMemento() { return memento; }
}
實務上發起人通常是 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 final Map<String, Object> stateMap;
public Memento(Map<String, Object> m) { stateMap = m; }
public Map<String, Object> getStateMap() { return stateMap; }
}
class BeanUtils {
public static Map<String, Object> backupProp(Object bean) { /* 內省讀取所有屬性 */ }
public static void restoreProp(Object bean, Map<String, Object> map) { /* 內省寫回 */ }
}
class Caretaker {
private final Map<String, Memento> memMap = new HashMap<>();
public void setMemento(String idx, Memento m) { memMap.put(idx, m); }
public Memento getMemento(String idx) { return memMap.get(idx); }
}
| 優點 | 缺點 |
|---|---|
| 提供狀態回滾機制,撤銷錯誤操作 | 多狀態多備份時記憶體佔用大 |
| 發起人無需管理歷史狀態,符合單一職責 | 頻繁建立備忘錄可能影響效能 |
適用場景:JDBC 交易回滾、文字編輯器 Ctrl+Z、棋類遊戲悔棋、表單多步驟導航回上一步等。