🔄 回顾 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):为语言构建解释器,对语法规则建模,实现表达式的解析与执行。