🔄 回顧 Day 17:中介者模式小結
在 Day 17 中,我們學習了中介者模式(Mediator Pattern):
- 用一個中介者集中管理對象之間的通信。
- 降低對象之間的耦合,適用于聊天系統、GUI 控件聯動、塔臺調度等。
今天進入一個非常貼近用戶操作體驗的設計模式——備忘錄模式(Memento Pattern)。
備忘錄模式:在不破壞封裝的前提下,保存對象的內部狀態,便于后續恢復到某一狀態。
它是“撤銷 / 恢復”操作背后的設計思想核心。
一、備忘錄模式的應用動機
在許多軟件中,我們都可以看到“撤銷(Undo)”、“恢復(Redo)”等功能:
- 文本編輯器可以撤銷幾次輸入
- 游戲中可以回到某個存檔
- 圖像處理工具支持操作歷史回退
這就要求:
- 程序能保存某個時刻的狀態
- 恢復時不依賴外部記錄
- 保證對象內部狀態的私有性(封裝)
? 所以我們引入備忘錄模式:由備忘錄(Memento)保存對象狀態,管理員(Caretaker)持有備忘錄,對象(Originator)可保存/恢復。
二、結構圖(UML)
+----------------+
| Originator |
+----------------+
| +createMemento |
| +restore(m) |
+----------------+|v
+----------------+
| Memento |
+----------------+
| state |
+----------------+^|
+----------------+
| Caretaker |
+----------------+
| history |
+----------------+
三、角色說明
角色 | 說明 |
---|---|
Originator | 發起人:定義要保存的狀態,并創建和恢復備忘錄 |
Memento | 備忘錄:存儲發起人對象的狀態,不提供修改接口 |
Caretaker | 管理者:保存備忘錄對象,不操作其內容,僅作管理使用 |
四、C++ 實現:文本編輯器 Undo 示例
我們模擬一個文本編輯器,每次輸入文本都可以保存當前狀態。
? Originator 類:TextEditor
class Memento {std::string state_;
public:Memento(const std::string& s) : state_(s) {}std::string getState() const { return state_; }
};class TextEditor {std::string text_;
public:void type(const std::string& newText) {text_ += newText;}std::shared_ptr<Memento> save() {return std::make_shared<Memento>(text_);}void restore(std::shared_ptr<Memento> m) {text_ = m->getState();}void show() const {std::cout << "當前內容:" << text_ << std::endl;}
};
? Caretaker:備忘錄棧
class Caretaker {std::stack<std::shared_ptr<Memento>> history_;
public:void backup(std::shared_ptr<Memento> m) {history_.push(m);}std::shared_ptr<Memento> undo() {if (!history_.empty()) {auto m = history_.top();history_.pop();return m;}return nullptr;}
};
? 使用示例
int main() {TextEditor editor;Caretaker caretaker;editor.type("Hello ");caretaker.backup(editor.save());editor.type("World!");caretaker.backup(editor.save());editor.type(" This should be undone.");editor.show();editor.restore(caretaker.undo());editor.show();editor.restore(caretaker.undo());editor.show();return 0;
}
輸出:
當前內容:Hello World! This should be undone.
當前內容:Hello World!
當前內容:Hello
五、實際項目中的應用場景
場景 | 應用說明 |
---|---|
編輯器(文本、圖像) | 操作歷史,撤銷恢復 |
游戲進度管理 | 存檔機制,一鍵恢復到特定狀態 |
配置參數修改 | 一鍵還原到默認參數或歷史設置 |
工作流狀態保存 | 在流程推進過程中保存流程中間狀態 |
數據庫事務管理 | 快照、事務回滾 |
六、優缺點分析
? 優點:
- 保留對象狀態,支持撤銷與恢復
- 不破壞封裝性,狀態由對象自身保存
- 多個備份版本可管理
? 缺點:
- 狀態快照可能占用較大內存
- 多次保存增加性能開銷
- 管理復雜,需注意備份何時保存/清理
七、與命令、原型模式對比
模式 | 意圖 | 特點 |
---|---|---|
備忘錄 Memento | 保存對象內部狀態 | 封裝狀態,支持恢復 |
命令 Command | 將操作封裝為對象,支持撤銷 | 記錄操作動作,而非對象狀態本身 |
原型 Prototype | 克隆對象 | 一般用于新對象創建,非狀態回滾 |
八、面試回答模板
“我們在圖像處理系統中使用備忘錄模式保存圖像編輯的中間狀態。每次用戶進行濾鏡、剪裁、調整操作時,會生成一個狀態快照,存入備忘錄棧。當用戶點擊撤銷時,恢復到上一個狀態。該方案確保封裝性,同時支持多層撤銷。”
? 強調:狀態封裝、用戶體驗、棧式回滾邏輯
九、口訣記憶
“封裝狀態不泄露,快照回滾不出錯;歷史棧中找快照,一鍵恢復沒煩惱。”
十、明日預告:Day 19
解釋器模式(Interpreter Pattern):為語言構建解釋器,對語法規則建模,實現表達式的解析與執行。