备忘录模式核心结构为:Originator(含私有State和createMemento/restoreFromMemento)、私有嵌套Memento(禁写、无public成员)、CareTaker(仅存储Memento)。

备忘录模式的核心结构怎么搭
备忘录模式本质是把对象的内部状态快照分离出来,不破坏封装的前提下支持撤销/恢复。C++里最直接的做法是:原对象(Originator)自己创建 Memento,但只暴露不可变的接口给管理者(CareTaker),而 Memento 本身用私有构造 + friend 或嵌套类来限制访问权限。
常见错误是让 Memento 暴露 set 方法,或者把状态成员设为 public——这等于白做,封装性就崩了。
推荐写法:
-
Memento是Originator的 私有嵌套类,构造函数和状态字段全private -
Originator提供createMemento()和restoreFromMemento(const Memento&)两个公有方法 -
CareTaker只负责存取Memento对象,完全不碰其内部数据
如何避免深拷贝带来的性能问题
如果 Originator 状态包含大块数据(比如 std::vector 或字符串缓存),每次 createMemento() 都完整拷贝,撤销频繁时开销明显。
可以改用“写时复制”或共享指针,但更稳妥的折中方案是:只在真正需要持久化时才拷贝,其余时候用移动语义减少临时对象。
示例关键片段:
class Originator {
private:
struct State { std::string content; int version; };
State current_;
public:
// 移动构造,避免冗余拷贝
Memento createMemento() { return Memento{std::move(current_)}; }
void restoreFromMemento(const Memento& m) {
current_ = m.state_; // 这里仍是拷贝,但仅发生在 restore 时
}
// ... 其他逻辑
};
注意:Memento 的构造参数如果是 State&&,要确保 Originator 当前状态允许被移走(即后续不会立刻再用);否则还是传 const State& 更安全。
为什么不能用 std::any 或 void* 存状态
有人想图省事,把状态塞进 std::any 或裸指针里,让 Memento 变成通用容器。这会导致三个实际问题:
- 类型信息丢失,
restoreFromMemento时必须手动std::any_cast,一旦类型不匹配就抛异常 -
void*完全绕过类型系统,编译器无法检查,运行时崩溃风险高 - 无法自动管理内存生命周期,容易悬垂或重复释放
备忘录不是序列化框架,它针对的是**单个类的可控状态**。老老实实用结构体或类封装状态字段,编译期就能保证类型安全,也方便调试时直接打印 Memento 内容。
多级撤销时 CareTaker 怎么管理 Memento 列表
CareTaker 通常用 std::vector 或 std::stack 存档。但要注意:如果用户连续撤销后又执行新操作,按标准模式应清空“未来”历史(即当前索引之后的所有存档)。
简单实现可用索引+vector:
class CareTaker {
std::vector<memento> history_;
size_t current_index_ = 0;
public:
void save(const Memento& m) {
// 清掉“未来”,然后追加新状态
history_.erase(history_.begin() + current_index_, history_.end());
history_.push_back(m);
++current_index_;
}
Memento undo() {
if (current_index_ > 0) --current_index_;
return history_[current_index_];
}
Memento redo() {
if (current_index_ + 1 <p>这里没做边界防护,真实项目里 <code>undo</code>/<code>redo</code> 返回 <code>std::optional<memento></memento></code> 更合适。另外,vector 的 erase 操作在大量存档时可能慢,真要高性能可换用链表或双端队列,但多数场景 vector 足够。</p>
<p>最容易被忽略的一点:Memento 对象本身应当是轻量、无外部依赖的值类型。如果它内部持有文件句柄、网络连接或智能指针指向全局资源,那 restore 就不只是“还原状态”,而是触发副作用——这就偏离了备忘录的本意。</p></memento>
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











