1.使用场景
有的时候需要恢复或回滚至某一对象的历史状态,例如游戏中种需要恢复到某一角色的某个阶段,版本控制中回复到某一提交阶段等
2.涉及到的角色
原发器(Originator)角色: 需要保存状态的对象,原发器根据需要决定将自己的内部状态保存到备忘录中(这里就确定了原发器需要一个备忘内部状态的方法),并可以使用备忘录来恢复内部状态(这里就确定了一个根据备忘录回滚rollback\恢复内部状态的方法)。
备忘录(Memento)角色: 负责存储原发器对象的内部状态,但是具体需要存储哪些内部状态是由原发器对象来决定的。另外备忘录应该只能由原发器对象来访问它内部的数据,原发器外部的对象不应该访问到备忘录对象的内部数据。
管理者(Caretaker)角色: 备忘录管理者/守护者。主要负责对备忘录对象的储存,但是不能对备忘录对象的内容进行操作或检查。
3.UML类图
4.关键代码
备忘录Memento
@Data
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
}
守护者/管理类CareTaker
public class CareTaker {
/**
* 存储备忘录对象的容器,容器可以为Stack、可以为Collection等其他存储性类
* 这里也就体现了备忘录的一个弊端:随着备忘录对象的增多,对内存的占用也变多
*/
private final Map<String, Memento> maps = new ConcurrentHashMap<>(16);
/**
* 获取备忘录对象
*
* @param state
* @return
*/
public Memento getMemento(String state) {
final Memento memento = maps.get(state);
return memento;
}
/**
* 保存备忘录对象
*
* @param memento
*/
public void addMemento(Memento memento) {
maps.put(memento.getState(), memento);
}
}
原发器类Originator
@Data
public class Originator {
private String state;
/**
* 保存对象的状态-生成备忘录记录
*
* @return
*/
public Memento saveStateToMemento() {
return new Memento(state);
}
/**
* 回滚
*
* @param memento
*/
public void rollback(Memento memento) {
this.state = memento.getState();
}
}
5.优缺点
备忘录模式的主要优点如下:
给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态
实现了内部状态的封装,使得用户不需要关心状态的保存细节
备忘录模式的主要缺点如下:
如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源
6.实际应用场景
1)rt.jar中的应用
2)spring-webflow中的使用
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>