模式定义:
在不破环封装行性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态。
模式场景
- 录入大批人员资料的时候。正在录入当前人资料时,发现上一个人录错了,此时需要恢复到上一个人的资料,进行修改。
- Word编辑时,忽然断电或电脑死机,再打开时,可以看到Word提示你恢复到以前的文档。
模式结构
模式结构-
Memento:备忘录。主要用来存储原发器对象的内部状态,但是具体需要存储哪些数据是由原发器对象来决定的。另外备忘录应该只能由原发器对象来访问它内部的数据,原发器外部的对象不应该能访问到备忘录对象的内部数据。
-
Originator:原发器。使用备忘录来保存某个时刻原发器自身的状态,也可以使用备忘录来恢复内部状态。
- Caretaker:备忘录管理者,或者称为备忘录负责人。主要负责保存备忘录对象,但是不能对备忘录对象的内容进行操作或检查。
代码实现
UML图
源码
public interface FlowAMockMemento {
}
public class FlowAMock {
private String flowName;
private int tempResult;
private String tempState;
public FlowAMock(String flowName) {
this.flowName = flowName;
}
public void runPhaseOne(){
tempResult = 3;
tempState = "phaseOne";
}
public void schema1(){
this.tempState += ",Schema1";
System.out.println(this.tempState+":now run " + tempResult);
this.tempResult += 11;
}
public void schema2(){
this.tempState += ",Schema2";
System.out.println(this.tempState+":now run " + tempResult);
this.tempResult += 22;
}
public FlowAMockMemento createMemento(){
return new MementoImpl(this.tempResult,this.tempState);
}
public void setMemento(FlowAMockMemento memento){
MementoImpl mementoImpl = (MementoImpl) memento;
this.tempResult = mementoImpl.getTempResult();
this.tempState = mementoImpl.getTempState();
}
/**
* 真正的备忘录对象,实现备忘录窄接口
* 实现成为私有内部类
*/
private static class MementoImpl implements FlowAMockMemento{
@Getter
private int tempResult;
@Getter
private String tempState;
public MementoImpl(int tempResult, String tempState) {
this.tempResult = tempResult;
this.tempState = tempState;
}
}
}
@Data
public class FlowAMementoCareTaker{
private FlowAMockMemento memento;
}
public class Client {
public static void main(String[] args) {
FlowAMock mock = new FlowAMock("testFlow");
mock.runPhaseOne();
FlowAMementoCareTaker careTaker = new FlowAMementoCareTaker();
FlowAMockMemento memento = mock.createMemento();
careTaker.setMemento(memento);
mock.schema1();
mock.setMemento(memento);
mock.schema2();
}
}
模式的优缺点
模式的优点
-
更好的封装性
备忘录模式通过使用备忘录对象,来封装原发器对象的内部状态,虽然这个对象是保存在原发器对象的外部,但是由于备忘录对象的窄接口并不提供任何方法,这样有效的保证了对原发器对象内部状态的封装,不把原发器对象的内部实现细节暴露给外部。
-
简化了原发器
备忘录模式中,备忘录对象被保存到原发器对象之外,让客户来管理他们请求的状态,从而让原发器对象得到简化。
-
窄接口和宽接口
模式的缺点
-
可能会导致高开销
备忘录模式基本的功能,就是对备忘录对象的存储和恢复,它的基本实现方式就是缓存备忘录对象。这样一来,如果需要缓存的数据量很大,或者是特别频繁的创建备忘录对象,开销是很大的。
思考
模式本质:保存和恢复内部状态
开发中的应用场景:
-
棋类游戏,悔棋
-
普通软件,撤销操作
-
数据库软件中的,事务管理的,回滚操作
-
Photoshop软件
相关模式
- 备忘录模式和命令模式
这两个模式可以组合使用。
命令模式实现中,在实现命令的撤销和重做的时候,可以使用备忘录模式,在命令操作的时候记录下操作前后的状态,然后在命令撤销和重做的时候,直接使用相应的备忘录对象来恢复状态就可以了。
在这种撤销的执行顺序和重做执行顺序可控的情况下,备忘录对象还可以采用增量式记录的方式,可以减少缓存的数据量。
- 备忘录模式和原型模式
这两个模式可以组合使用。
在原发器对象创建备忘录对象的时候,如果原发器对象中全部或者大部分的状态都需要保存,一个简洁的方式就是直接克隆一个原发器对象。也就是说,这个时候备忘录对象里面存放的是一个原发器对象的实例。
网友评论