备忘录模式
1/27/24About 5 min
备忘录模式可以保持对象状态的快照,这样对象可以在不向外界公开其内容的情况下返回到它的最初状态。

备忘录模式的主要角色:
- 发起人(Originator) - 需要保存状态的对象。它可以创建一个备忘录,用来记录当前时刻的内部状态。
- 备忘录(Memento) - 用于存储发起人对象的内部状态。
- 管理者(Caretaker) - 管理Memento角色,负责保存好备忘录。
代码实现
发起人
发起人持有需要保存的状态,并且提供创建备忘录,和恢复状态的方法。
public class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return this.state;
}
public void setMemento(Memento memento) {
// 恢复状态
this.state = memento.getState();
}
public Memento createMemento() {
return new Memento(this.state);
}
}备忘录
备忘录中持有状态字段,用于记录发起人的状态。
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return this.state;
}
}管理者
管理者通过mementoList记录所有的状态变化,可以将发起人的状态还原到任意时刻。
public class Caretaker {
private List<Memento> mementoList = new ArrayList<Memento>();
public void add(Memento state) {
mementoList.add(state);
}
public Memento get(int index) {
return mementoList.get(index);
}
}使用方法
通过发起人对象来创建备忘录,并且通过管理者对象来保存备忘录。
每次发起人状态改变的时候,我们都通过originator.createMemento创建当前状态的备忘录;之后通过caretaker.add记录备忘录。
状态还原时,通过caretaker.get获取某个时刻的备忘录,通过originator.setMemento恢复状态。
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State #1");
caretaker.add(originator.createMemento());
originator.setState("State #2");
caretaker.add(originator.createMemento());
originator.setState("State #3");
caretaker.add(originator.createMemento());
originator.setMemento(caretaker.get(0));
System.out.println(originator.getState());
originator.setMemento(caretaker.get(1));
System.out.println(originator.getState());
originator.setMemento(caretaker.get(2));
System.out.println(originator.getState());
}
}结果:

备忘录模式与其他模式的对比
| 模式 | 功能 | 实现方式 | 适用场景 |
|---|---|---|---|
| 备忘录模式 | 保存和恢复对象状态 | 外部存储对象状态,不破坏封装性 | 需要支持对象状态的保存和恢复时 |
| 命令模式 | 封装请求为对象 | 将请求封装为命令,支持队列、撤销等 | 需要支持请求的队列化、日志记录或撤销时 |
| 状态模式 | 封装对象状态行为 | 对象状态变化时改变其行为 | 对象行为依赖于其状态,且状态可动态变化时 |
| 原型模式 | 通过复制创建对象 | 创建对象副本,包括其当前状态 | 需要创建对象副本且复制过程复杂时 |
总结
核心思想
备忘录模式的核心思想是在不破坏封装性的前提下,捕获一个对象的内部状态并在需要时恢复它。它通过外部化存储对象状态,实现了对象状态的保存与恢复,同时保持了对象的封装性。
主要角色
- 发起人(Originator):需要保存状态的对象,提供创建备忘录和恢复状态的方法
- 备忘录(Memento):存储发起人对象的内部状态,通常只对发起人可见
- 管理者(Caretaker):管理备忘录,负责保存和提供备忘录,但不操作备忘录内容
实现方式
- 发起人定义创建备忘录和恢复状态的方法
- 备忘录类存储发起人的内部状态,提供状态访问方法
- 管理者类管理备忘录集合,支持添加和获取备忘录
- 客户端通过发起人创建备忘录,通过管理者保存备忘录,需要时通过管理者获取备忘录并恢复发起人状态
优缺点
优点:
- 符合单一职责原则,状态保存和恢复逻辑与业务逻辑分离
- 保持了对象的封装性,外部无法直接访问对象内部状态
- 提供了状态恢复机制,支持撤销操作
- 实现了状态的外部化存储,减少了对象的内存占用
缺点:
- 如果对象状态复杂,备忘录可能会占用大量内存
- 管理者需要管理大量备忘录,可能导致系统性能下降
- 备忘录与发起人之间存在耦合,发起人状态变化时可能需要修改备忘录
- 可能违反接口隔离原则,备忘录可能暴露不必要的内部状态
适用场景
- 需要支持对象状态的保存和恢复操作
- 希望保持对象的封装性,不暴露其内部状态
- 需要实现撤销/重做功能
- 需要记录对象状态的历史变化
- 需要在特定时间点保存对象状态,以便后续恢复
实际应用
- 文本编辑器的撤销/重做功能:保存文档的历史状态,支持撤销和重做操作
- 游戏存档功能:保存游戏角色和场景的状态,支持加载存档
- 数据库事务回滚:保存事务执行前的状态,失败时回滚到原始状态
- 浏览器的前进/后退功能:保存浏览历史状态,支持前进和后退操作
- 配置文件的版本管理:保存配置文件的历史版本,支持恢复到特定版本