Demo 地址: https://github.com/ooblee/HelloDesignPattern
1. 定义
备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。
其实就是状态的存储和复原
2. 设计
主要角色:
- 原发器(Originator),可以把内部状态创建为备忘录,然后用备忘录来恢复内部状态。
- 备忘录(Memento),存储原发器的状态,只供原发器和负责人使用。
- 负责人(Caretaker),保存备忘录,但不能进行修改和检查。
类图如下:
简单的模型如下。
原发器 Originator,存在内部状态,并提供接口进行状态的保存和复原。
public class Originator {
public int state;
public Memento saveMemento() {
Memento memento = new Memento();
memento.setState(state);
return memento;
}
public void restoreMemento(Memento memento) {
this.state = memento.getState();
}
public void setState(int state) {
this.state = state;
}
public int getState() {
return state;
}
}
备忘录 Memento,对原发器需要存储和复原的状态进行保存。
public class Memento {
private int state;
public void setState(int state) {
this.state = state;
}
public int getState() {
return state;
}
}
负责人 Caretaker,只做备忘录的存储。
public class Caretaker {
private Memento memento;
public Caretaker() {
}
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
客户端的调用,状态切换前都会保存一下之前的状态,在某个时间段用来复原。
public class TestMemento {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Originator originator = new Originator();
// 转移到状态 1
originator.setState(1);
System.out.println("state:" + originator.getState());
// 转移到状态 2
caretaker.setMemento(originator.saveMemento());
originator.setState(2);
System.out.println("state:" + originator.getState());
// 转移到状态 3
caretaker.setMemento(originator.saveMemento());
originator.setState(3);
System.out.println("state:" + originator.getState());
// 回退到状态 2
originator.restoreMemento(caretaker.getMemento());
System.out.println("state:" + originator.getState());
}
}
2.1. 多次撤销
把负责人存储备忘录的数据结构调整一下,改成堆、栈、队列等。
2.2. 备忘录的封装
因为备忘录只允许原发器和负责人访问,不允许其他对象访问和修改,可以通过语言的一些特性实现。
Java 的一些方式:
- 备忘录和原发器放同一个包,备忘录为包可见。
- 备忘录直接作为原发器的内部类。
3. 应用
适用场景:
- 需要保存状态并且进行回滚。实现单次撤销或者多次撤销操作。
- 封装状态,防止外界破坏。
4. 特点
4.1. 优点
- 可恢复,对状态恢复提供了一种实现机制。
- 封装状态,原发器的状态被封装起来不会被外界修改到。
4.2. 缺点
- 资源消耗,如果原发器需要存储和恢复的对象多且占用内存大,使用备忘录会增加系统内存消耗。