1: 宽接口和白箱:
2: 发起人角色
3: public class Originator{ 4: private String state;
5:
6: //工厂方法,返还一个新的备忘录对象
7: public Memento createMemento(){ 8: return new Memento(state);
9: }
10:
11: //将发起人恢复到备忘录对象所记载的状态
12: public void restoreMemento(Memento memento){ 13: this.state = memento.getState();
14: }
15:
16: //状态的取值方法
17: public String getState(){ 18: return this.state;
19: }
20:
21: //状态的赋值方法
22: public void setState(String state){ 23: this.state = state;
24: System.out.println("Current state = " + this.state); 25: }
26: }
27:
28: 备忘录模式要求备忘录对象提供两个不同的接口:一个宽接口提供给发起人对象,另一个窄接口提供给所有其他的对象,包括负责人对象。
29: 宽接口允许发起人读取到所有的数据;窄接口只允许它把备忘录对象传给其他的对象而看不到内部的数据。
30: //备忘录角色
31: public class Memento{ 32: private String state;
33:
34: public Memento(String state){ 35: this.state = state;
36: }
37:
38: public String getState(){ 39: return this.state;
40: }
41:
42: public void setState(String state){ 43: this.state = state;
44: }
45: }
46:
47: 负责人角色负责保存备忘录对象,但是从不修改(甚至不查看)备忘录对象的内容(一个更好的实现是负责人对象根本无法从备忘录
48: 对象中读取个修改其内容)
49:
50: //负责人角色
51: public class Caretaker{ 52: private Memento memento;
53:
54: //备忘录的取值方法
55: public Memento retrieveMemento(){ 56: return this.memento;
57: }
58:
59: //备忘录的赋值方法
60: public void saveMemento(Memento memento){ 61: this.memento = memento;
62: }
63: }
64:
65: //客户端
66: public class Client{ 67: private static Originator o = new Originator();
68: private static Caretaker c= new Caretaker();
69: private static void main(String[] args){ 70: //该负责人对象的状态
71: o.setState("On"); 72: //创建备忘录对象,并将发起人对象的状态存储起来
73: c.saveMemento(o.createMemento());
74: //修改发起人对象的状态
75: o.setState("Off"); 76: //恢复发起人对象的状态
77: o.restoreMemento(c.retrieveMemento());
78: }
79: }
80: 首先将发起人对象的状态设置成“On”(或者任何有效状态),并且创建一个备忘录对象将这个状态存储起来;然后将发起人对象
81: 的状态改成“Off”(或者任何状态);最后又将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态(或者先前所
82: 存储的任何状态)
83:
84: 备忘录系统运行的时序是这样的:
85: (1)将发起人对象的状态设置成“On”。
86: (2)调用发起人角色的createMemento()方法,创建一个备忘录对象将这个状态存储起来。
87: (3)将备忘录对象存储到负责人对象中去。
88: 备忘录系统恢复的时序是这样的:
89: (1)将发起人对象的状态设置成“Off”;
90: (2)将备忘录对象从负责人对象中取出;
91: (3)将发起人对象恢复到备忘录对象所存储起来的状态,“On”状态。
92:
93: 白箱实现的优缺点
94: 白箱实现的一个明显的好处是比较简单,因此常常用做教学目的。白箱实现的一个明显的缺点是破坏对发起人状态的封装。
95:
96: 窄接口或者黑箱实现
97: //发起人角色
98: public class Originator{ 99: private String state;
100:
101: public Originator(){ 102: }
103:
104: //工厂方法,返还一个新的备忘录对象
105: public MementoIF createMemento(){ 106: return new Memento(this.state);
107: }
108:
109: //将发起人恢复到备忘录对象记录的状态
110: public void restoreMemento(MementoIF memento){ 111: Memento aMemento = (Memento)memento;
112: this.setState(aMemento.getState());
113: }
114:
115: public String getState(){ 116: return this.state;
117: }
118:
119: public void setState(){ 120: this.state = state;
121: System.out.println("state = " + state); 122: }
123:
124: protected class Memento implements MementoIF{ 125: private String savedState;
126: private Mememto(String someState){ 127: savedState = someState;
128: }
129:
130: private void setState(String someState){ 131: savedState = someState;
132: }
133:
134: private String getState(){ 135: return savedState;
136: }
137: }
138: }
139:
140: public interface MementoIF{} 141:
142: public class Caretaker{ 143: private MementoIF memento;
144:
145: public MementoIF retrieveMemento(){ 146: return this.memento;
147: }
148:
149: public void saveMemento(MementoIF memento){ 150: this.memento = memento;
151: }
152: }
153:
154: public class Client{ 155: private static Originator o = new Originator();
156: private static Caretaker c = new Caretaker();
157:
158: public static void main(String args[]){ 159: //改变负责人对象的状态
160: o.setState("On"); 161: //创建备忘录对象,并将发起人对象的状态存储起来
162: c.saveMemento(o.createMemento());
163: //修改发起人对象的状态
164: o.setState("Off"); 165: //恢复发起人对象的状态
166: o.restoreMemento(c.retrieveMemento());
167: }
168: }
169:
170: 黑箱实现运行时的时序为;
171: (1)将发起人对象的状态设置成“On”。
172: (2)调用发起人角色的 createMemento()方法,创建一个备忘录对象将这个状态存储起来。
173: (3)将备忘录对象存储到负责人对象中去。由于负责人对象拿到的仅是 MementoIF类型,因此无法读出备忘录内部的状态。
174: 恢复时的时序为:
175: (1)将发起人对象的状态设置成“Off”;
176: (2)将备忘录对象从负责人对象中取出。注意此时仅能得到 MementoIF接口,因此无法读出此对象的内部状态
177: (3)将发起人对象的状态恢复成备忘录对象所存储起来的状态,,由于发起人对象的内部类Memento实现了MementoIF接口
178: 这个内部类是传入的备忘录对象的真实类型,因此发起人对象可以利用内部类Memento 的私有 接口读出此对象的内部状态
179:
180: 存储多个状态的备忘录模式:
181: //发起人角色
182: import java.util.Vector;
183: import java.util.Enumeration;
184:
185: public class Originator{ 186: private Vector states;
187: private int index;
188:
189: public Originator(){ 190: states = new Vector();
191: index = 0;
192: }
193:
194: public Memento createMementor(){ 195: return new Mementor(states,index);
196: }
197:
198: public void restoreMementor(Mementor memento){ 199: states = memento.getStates();
200: index = memento.getIndex();
201: }
202:
203: public void setState(String state){ 204: this.states.addElement(state);
205: index ++;
206: }
207:
208: //辅助方法,打印出所有的状态
209: public void printStates(){ 210: System.out.println("Total number of states: " + index); 211: for(Enumeration e = states.elements();e.hasMoreElements();){ 212: system.out.println(e.nextElement());
213: }
214: }
215: }
216:
217: //备忘录角色
218: import java.util.Vector;
219:
220: public class Memento{ 221: private Vector states;
222: private int index;
223:
224: public Memento(Vector states,int index){ 225: this.states = (Vector)states.clone();
226: this.index = index;
227: }
228:
229: //状态取值方法
230: Vector getStates(){ 231: return states;
232: }
233:
234: //检查点取值方法
235: int getIndex(){ 236: return this.index;
237: }
238: }
239: ******************备忘录的构造子克隆了传入的states,然后将克隆存入到备忘录对象内部,这是一个重要的细节,因为不这样的话,将会
240: 将会造成客户端和备忘录对象持有对同一个Vector对象的引用,也可以同时修改这个Vector对象,会造成系统崩溃。
241:
242: //负责人角色
243: import java.util.Vector;
244:
245: public class Caretaker{ 246: private Originator o;
247: private Vector mementos = new Vector();
248: private int current;
249:
250: public Caretaker(Originator o){ 251: this.o = o;
252: current = 0;
253: }
254:
255: public int createMemento(){ 256: Memento memento = o.createMemento();
257: mementos.addElement(memento);
258: return current ++;
259: }
260:
261: //将发起人恢复到某个检查点
262: public void restoreMemento(int index){ 263: Memento memento = (Memento)mementos.elementAt(index);
264: o.restoreMemento(memento);
265: }
266:
267: //某个检查点删除
268: public void removeMemento(int index){ 269: mementos.removeElementAt(index);
270: }
271: }
272:
273: //客户端
274: public class Client{ 275: private static Originator o = new Originator();
276: private static Caretaker c = new Caretaker(o);
277: public static void main(String[] args){ 278: //改变状态
279: o.setState("state 0"); 280: //建立一个检查点
281: c.createMemento();
282: //改变状态
283: o.setState("state 1"); 284:
285: c.createMemento();
286:
287: o.setState("state 2"); 288:
289: c.createMemento();
290:
291: o.setState("state 3"); 292:
293: c.createMemento();
294:
295: o.setState("state 4"); 296:
297: c.createMemento();
298:
299: o.printStates();
300:
301: //恢复到第二个检查点
302: System.out.println("Restoring to 2"); 303:
304: c.restoreMemento(2);
305:
306: o.printStates();
307:
308: System.out.println("Restoring to 0"); 309:
310: c.restoreMemento(0);
311:
312: o.printStates();
313:
314: System.out.println("Restoring to 3"); 315:
316: c.restoreMemento(3);
317:
318: o.printStates();
319:
320:
321: }
322: }
323:
324: 自述历史模式(备忘录模式的一个变种):
325: //窄接口
326: public interface MementoIF{} 327:
328: //发起人角色
329: public class Originator{ 330: public String state;
331:
332: public Originator(){} 333:
334: public void changeState(String state){ 335: this.state = state;
336: System.out.println("State has been changed to : " + state); 337: }
338:
339: public Memento createMemento(){ 340: return new Memento(this);
341: }
342:
343: public void restoreMemento(MementoIF memento){ 344: Memento m = (Memento)memento;
345: changeState(m.state);
346: }
347:
348: class Memento implements MementoIF{ 349: private String state;
350:
351: private String getState(){ 352: return state;
353: }
354:
355: private Memento(Originator o){ 356: this.state = o.state;
357: }
358: }
359: }
360:
361: //客户端
362: public class Client{ 363: private static Originator o;
364: private static MementoIF memento;
365:
366: public static void main(String args[]){ 367: o = new Originator();
368: o.changeState("State 1"); 369: memento = o.createMemento();
370: o.changeState("State 2"); 371: o.restoreMemento(memento);
372: }
373: }
374: