C++ 备忘录模式实战:对象状态保存与恢复
在开发过程中,我们常会遇到需要撤销操作、历史记录或状态回滚的场景。备忘录模式(Memento Pattern)正是解决这类问题的经典方案。它允许在不破坏封装性的前提下,捕获并外部化对象的内部状态,以便后续恢复。
核心角色解析
实现备忘录模式主要涉及三个角色,理解它们的职责是上手的关键。
1. Originator(发起人)
这是需要保存状态的对象。它负责创建备忘录并记录当前状态,同时也能利用备忘录恢复到之前的状态。简单来说,它是状态的拥有者。
2. Memento(备忘录)
这是存储状态的容器。它有两个接口:宽接口供 Originator 使用以存取数据,窄接口供其他对象使用仅用于读取。这种设计确保了状态细节的封装性不被破坏。
3. Caretaker(管理者)
负责管理备忘录对象,比如保存列表。关键点在于,Caretaker 不操作备忘录内容,只能通过窄接口交互,避免越权访问。
设计原则体现
这个模式很好地体现了几个面向对象原则:
- 单一职责:将状态保存从业务逻辑中剥离,Originator 更专注核心功能。
- 开闭原则:扩展保存功能无需修改 Originator,新增备忘录类即可。
- 迪米特法则:Caretaker 不直接触碰 Memento 内部细节,降低耦合。
C++ 实现示例
下面是一个完整的 C++ 实现。注意这里使用了友元机制来保证 Memento 对 Originator 的可见性,同时通过窄接口限制外部访问。
#include <iostream>
#include <string>
#include <vector>
// 备忘录类
class Memento {
private:
std::string state;
// 只有 Originator 可以访问私有成员
friend class Originator;
Memento(const std::string& s) : state(s) {}
std::string GetState() const { return state; }
};
// 发起人类
class Originator {
private:
std::string state;
public:
void SetState(const std::string& s) {
std::cout << "设置状态:" << s << std::endl;
state = s;
}
Memento* CreateMemento() {
return new Memento(state);
}
void RestoreFromMemento(const Memento* m) {
state = m->GetState();
std::cout << "恢复状态:" << state << std::endl;
}
};
// 管理者类
class Caretaker {
private:
std::vector<Memento*> mementos;
Originator* originator;
public:
Caretaker(Originator* orig) : originator(orig) {}
~Caretaker() {
for (auto m : mementos) delete m;
}
void Save() {
mementos.push_back(originator->CreateMemento());
}
void Undo() {
if (mementos.empty()) return;
Memento* m = mementos.back();
originator->RestoreFromMemento(m);
mementos.pop_back();
delete m;
}
};
// 使用示例
int main() {
Originator originator;
Caretaker caretaker(&originator);
originator.SetState("状态 1");
caretaker.Save();
originator.SetState("状态 2");
caretaker.Save();
originator.SetState("状态 3");
// 执行撤销,恢复到状态 2
caretaker.Undo();
// 再次撤销,恢复到状态 1
caretaker.Undo();
return 0;
}
在实际工程中,考虑到内存安全,建议配合智能指针使用,或者在析构函数中确保资源释放,避免内存泄漏。
典型应用场景
备忘录模式适合以下场景:
- 撤销/重做功能:如文本编辑器的 Ctrl+Z。
- 事务回滚系统:数据库操作失败时恢复现场。
- 游戏存档系统:保存进度快照。
- 配置管理:保留配置的历史版本。
高级特性与优化
1. 增量备忘录
如果状态变化不大,只保存差异部分能显著减少内存消耗。
2. 序列化支持
通过序列化技术,可以将备忘录持久化到文件或数据库,实现跨会话的状态恢复。
3. 线程安全考虑
多线程环境下使用时,需添加锁机制保证状态一致性。
与其他模式的协作
备忘录模式常与其他模式配合:
- 命令模式:结合实现可撤销的操作栈。
- 原型模式:通过克隆优化备忘录创建过程。
- 状态模式:保存不同状态配置。
注意事项
- 内存消耗:大对象频繁保存可能导致内存压力,需评估频率和大小。
- C++ 内存管理:手动管理指针时需格外小心,推荐使用 RAII 机制。
- 替代方案:对于简单对象,原型模式可能更轻量。
总结
备忘录模式通过状态封装实现了灵活的回滚机制,是提升系统可维护性和扩展性的有效手段。在 C++ 中实现时,重点在于平衡封装性与内存安全。掌握这一模式,能让你的代码在处理历史状态时更加稳健。

