支持作者新书,点击京东购买《Yocto项目实战教程:高效定制嵌入式Linux系统》
设计模式每日硬核训练 Day 18:备忘录模式(Memento Pattern)完整讲解与实战应用
🔄 回顾 Day 17:中介者模式小结
在 Day 17 中,我们学习了中介者模式(Mediator Pattern):
- 用一个中介者集中管理对象之间的通信。
- 降低对象之间的耦合,适用于聊天系统、GUI 控件联动、塔台调度等。
今天进入一个非常贴近用户操作体验的设计模式——备忘录模式(Memento Pattern)。
备忘录模式:在不破坏封装的前提下,保存对象的内部状态,便于后续恢复到某一状态。
一、练习题与核心对比问答
✍️ 练习题一:文本状态保存器
设计一个备忘录系统用于撤销对用户输入内容的修改。要求实现:
- 用户每次输入时可调用 save() 保存状态
- 多次 undo() 恢复前几次的文本内容
- 使用 C++ 编写
Originator
、Memento
、Caretaker
三类结构
✍️ 练习题二:图形编辑器撤销操作
请使用备忘录模式为一个图形编辑器设计撤销机制,支持“图形形状位置”修改后还原。思考:
- 哪些属性需要保存?
- 如何让多个图形分别拥有备份能力?
- 如何将图形的状态封装为快照?
✍️ 面试问答题一:备忘录模式和原型模式的区别?
答:
- 原型模式用于快速“复制”一个对象,一般用于创建新对象(构造克隆)
- 备忘录模式用于“回滚”对象状态,用于历史恢复,而不是生成新对象
✍️ 面试问答题二:备忘录模式是否破坏封装?
答: 备忘录设计的初衷就是保护封装性。对象状态由自己负责快照保存,Caretaker
管理备份但不能访问其内容,Memento 类不提供 setState()
方法,从而保证了数据不可被外部修改。
二、结构图(UML)
+----------------+
| Originator |
+----------------+
| +createMemento |
| +restore(m) |
+----------------+
|
v
+----------------+
| Memento |
+----------------+
| state |
+----------------+
^
|
+----------------+
| Caretaker |
+----------------+
| history |
+----------------+
三、角色说明
角色 | 说明 |
---|---|
Originator | 发起人:定义要保存的状态,并创建和恢复备忘录 |
Memento | 备忘录:存储发起人对象的状态,不提供修改接口 |
Caretaker | 管理者:保存备忘录对象,不操作其内容,仅作管理使用 |
四、C++ 实现:文本编辑器 Undo 示例
我们模拟一个文本编辑器,每次输入文本都可以保存当前状态,并支持多次撤销操作。
✅ Memento:备忘录类
class Memento {
std::string state_;
public:
Memento(const std::string& s) : state_(s) {}
std::string getState() const { return state_; }
};
✅ Originator:文本编辑器类
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) {
if (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
这一示例展示了备忘录模式如何帮助我们在不暴露内部细节的情况下进行多次撤销,实用且易于维护。
…
十、明日预告:Day 19
解释器模式(Interpreter Pattern):为语言构建解释器,对语法规则建模,实现表达式的解析与执行。