备忘录模式
在不破坏封装性的前提下,保存一个对象需要保存的内部状态,并且在这个对象之外的地方将这些内部状态保存起来。当这个对象需要回归原来的状态时,可以通过保存起来的状态恢复到原来的状态。当你可能需要将对象的状态恢复到原来的状态时,就可以使用备忘录模式。
类型:
行为型模式(类的状态的行为型模式)
备忘录模式的几个角色:
- 发起者对象(Originator):创建Memento对象,并决定需要Memento对象需要保存Originnator的哪些内部状态。
- 备忘录对象(Memento):存储Originator对象需要保存的内部状态,并且防止除了Originator对象以为的其他对象访问Memento对象。
- 负责人对象(Caretaker):存储Memento对象,但不能对Memento对象进行查看或者修改操作。
备忘录模式的关系图:
备忘录模式示例:
发起者对象:
/**
* Create by zhaihongwei on 2018/3/31
* 发起者对象
*/
public class Originator {
// 内部状态,可以是很多个。
private String importantState;
private String commonState;
public String getImportantState() {
return importantState;
}
public void setImportantState(String importantState) {
this.importantState = importantState;
}
public String getCommonState() {
return commonState;
}
public void setCommonState(String commonState) {
this.commonState = commonState;
}
/**
* 创建Memento对象,并且将需要保存的状态,保存到Memento对象中
* @return
*/
public Memento createMemento() {
return new Memento(importantState);
}
/**
* 恢复到以前状态的方法
* @param memento
*/
public void restoreState(Memento memento) {
this.importantState = memento.getState();
}
/**
* toString,为了测试
* @return
*/
@Override
public String toString() {
return "Originator{" +
"importantState='" + importantState + '\'' +
", commonState='" + commonState + '\'' +
'}';
}
}
备忘录对象:
/**
* Create by zhaihongwei on 2018/3/31
* 备忘录对象
*/
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
负责人对象:
/**
* Create by zhaihongwei on 2018/3/31
* 负责人对象
*/
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
测试类:
/**
* Create by zhaihongwei on 2018/3/31
*/
public class MementoTest {
public static void main(String[] args) {
Originator originator = new Originator();
originator.setImportantState("重要属性");
originator.setCommonState("普通属性");
System.out.println(originator);
Memento memento = originator.createMemento();
// 将Memento对象保存起来
Caretaker caretaker = new Caretaker();
caretaker.setMemento(memento);
originator.setImportantState("改变的重要属性");
originator.setCommonState("改变了普通属性");
System.out.println(originator);
System.out.println("操作失误,重要属性不能修改,我需要恢复");
originator.restoreState(caretaker.getMemento());
System.out.println(originator);
}
}
测试结果:
Originator{importantState='重要属性', commonState='普通属性'}
Originator{importantState='改变的重要属性', commonState='改变了普通属性'}
操作失误,重要属性不能修改,我需要恢复
Originator{importantState='重要属性', commonState='改变了普通属性'}
总结:
有人可能会想到原型模式中的使用的clone的方式,或者命令模式中的撤销命令操作都可以做到将对象的状态保存并恢复原状态的效果,但是这两种方式对于属性恢复的功能都没有备忘录方式灵活,通过上面的例子,可以看到相对于原型模式,备忘录模式可以根据需求将需要进行保存的状态进行保存;相对于命令模式的撤销操作,有时候有些状态只能由发起者才能进行修改,而备忘录模式则通过宽窄接口的方式进行了实现。
关于Memento宽窄接口的理解:
宽接口:
- Memento对象向Originator对象提供了一种宽接口的方式,允许Originator访问并返回需要的数据。
窄接口:
- Memento对象向Caretaker对象提供了一种窄接口的方式,Caretaker对象只能进行Memento对象的传递,并不能修改Memento对象的内部状态。
备忘录模式的优缺点:
优点:
- 能够将重要的数据进行封装。
- 提供了容易恢复状态的方法。
- 只能由发起者进行状态的恢复和访问,避免其他对象访问。
缺点:
- 内部状态的存储过程可能是相当耗时的。
- 维护成本较高,负责人并不知道备忘录中保存了多少数据。