C++ 备忘录模式:一个可撤销状态的实现与权衡
写代码久了,总会遇到需要回退的场景——编辑器里的 Ctrl+Z,数据库事务失败时的现场恢复,或者游戏里的存档/读档。这些需求背后都藏着同一个模式:备忘录(Memento)。它能让你把对象内部状态抓取出来,保存在外部,日后还能原封不动地塞回去,而且全程不破坏对象的封装。
C++ 的实现尤其需要注意内存管理和访问权限。下面我会先交代角色分工,再给一个我自己常用的实现,最后聊聊实际工程里容易踩的坑和取舍。
角色分工
备忘录模式就三个角色,理解它们的职责比背定义有用得多。
Originator(发起人)——需要存档的那个对象。它创建备忘录来保存当前状态,也能用备忘录恢复状态。状态的拥有者。
Memento(备忘录)——状态的容器。它对外暴露两个不同'宽度'的接口:宽接口供 Originator 完全访问内部数据,窄接口对其他对象只开放有限操作(甚至只是传输句柄)。在 C++ 里,这个通常靠友元实现。
Caretaker(管理者)——负责保存一串备忘录(比如历史栈),但它不能窥探、修改备忘录内容,只能通过窄接口拿到备忘录并交给 Originator 恢复。
这三者的协作,核心就是把状态的存取与状态的持有解耦,让 Originator 不用暴露出 set/get 接口也能被外部回滚。
一个可以直接用的实现
#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;
}
{
(state);
}
{
state = m->();
std::cout << << state << std::endl;
}
};
{
:
std::vector<Memento*> mementos;
Originator* originator;
:
(Originator* orig) : (orig) {}
~() {
( m : mementos) m;
}
{
mementos.(originator->());
}
{
(mementos.()) ;
Memento* m = mementos.();
originator->(m);
mementos.();
m;
}
};
{
Originator originator;
;
originator.();
caretaker.();
originator.();
caretaker.();
originator.();
caretaker.();
caretaker.();
;
}


