備忘錄模式/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]