备忘录模式/Memento
意图/适用场景:
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。
备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并存储起来。在将来合适的时候把这个对象还原到存储时的状态。
UML:
参与者:
- 发起人(Originator):需要保存自身状态的对象。它有两个功能,一是创建新的备忘录,一是恢复到已有的备忘录。
- 管理者(Caretaker):负责管理备忘录,最主要的功能有两个:一是把备忘录存储起来,一是从存储设备中读取备忘录。
- 备忘录接口(Memento):备忘录的公共接口,不提供任何方法。
- 备忘录宽接口(MementoWideIF):这一接口是给Originator使用的,主要面向状态管理的功能,提供读写状态的方法。
- 备忘录窄接口(MementoNarrowIF):这一接口是给Caretaker使用的,主要面向存储功能,提供序列化的方法。
- 具体备忘录(ConcreteMemento):同时实现宽窄两个接口,同时提供状态读写和序列化的功能。
要点:
本模式里一个关键的地方在于ConcreteMemento角色同时实现了MementoWideIF和MementoNarrowIF两个接口。之所以这样设计是出于接口隔离的考虑。Originator即状态的使用者不关心备忘录如果被存储;而管理者也不应该看到与状态有关的细节,它只关心备忘录的存储。所以最好让它们分别面向不同的接口,互相不知道另一方以及另一套接口的存在。
应用实例:
电视游戏中的save/load功能是一个很好的例子。当玩家保存游戏进度时,就相当于建立了一份备忘录并把它存储起来,当然玩家可以建立不只一份的备忘录。
当再次游戏时,可以从已保存的多个进度中选择一个,继续游戏,这时就相当于把游戏场景恢复到保存时的状态。
示例代码:
[java]
// Source code from file:Caretaker.java
packagedesignPatterns.Memento;
publicclass Caretaker {
publicvoid saveMemento(Memento m) {
MementoNarrowIF mn =(MementoNarrowIF)m;
mn.serialize();
}
publicMemento loadMemento() {
// This is just for demo.
// Caretaker don't know ConcreteMemento. It just get a Memento from other place.
returnnew ConcreteMemento();
}
}
// Source code from file:ConcreteMemento.java
packagedesignPatterns.Memento;
publicclass ConcreteMemento implements MementoWideIF, MementoNarrowIF {
privateint state = 0;
publicint getState() {
returnstate;
}
publicvoid setState(int state) {
this.state= state;
}
publicvoid serialize() {
System.out.println("Memento was serialized.");
}
}
// Source code from file:Memento.java
packagedesignPatterns.Memento;
publicinterface Memento {
}
// Source code from file:MementoNarrowIF.java
packagedesignPatterns.Memento;
publicinterface MementoNarrowIF extends Memento {
publicvoid serialize();
}
// Source code from file:MementoWideIF.java
packagedesignPatterns.Memento;
publicinterface MementoWideIF extends Memento {
publicvoid setState(int state);
publicint getState();
}
// Source code from file:Originator.java
packagedesignPatterns.Memento;
publicclass Originator {
privateint state = 0;
publicMemento createMemento() {
ConcreteMemento m =new ConcreteMemento();
m.setState(state);
System.out.println("create memento with state "state);
returnm;
}
publicvoid restoreMemento(Memento m) {
MementoWideIF mw =(ConcreteMemento)m;
state = mw.getState();
System.out.println("restore memento with state "state);
}
}
// Source code from file:User.java
packagedesignPatterns.Memento;
publicclass User {
publicstatic void main(String[] args) {
Originator o =new Originator();
Caretaker c =new Caretaker();
// save memento
Memento m = o.createMemento();
c.saveMemento(m);
// load memento
m = c.loadMemento();
o.restoreMemento(m);
}
}
[/java]