小A:“那‘月光宝盒’备忘录模式有哪些组成部分?”
大B:“1、备忘录(Memento)角色:备忘录角色存储‘备忘发起角色’的内部状态。‘备忘发起角色’根据需要决定备忘录角色存储‘备忘发起角色’的哪些内部状态。为了防止‘备忘发起角色’以外的其他对象访问备忘录。 备忘录实际上有两个接口,‘备忘录管理者角色’只能看到备忘录提供的窄接口——对于备忘录角色中存放的属性是不可见的。‘备忘发起角色’则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。2、备忘发起(Originator)角色:‘备忘发起角色’创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。3、备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。称它为宽接口;而另一个则可以只是一个标示,称它为窄接口。 备忘录角色要实现这两个接口类。这样对于‘备忘发起角色’采用宽接口进行访问,而对于其他的角色或者对象则采用窄接口进行访问。这种实现比较简单,但是需要人为的进行规范约束——而这往往是没有力度的。第二种方法便很好的解决了第一种的缺陷:采用内部类来控制访问权限。将备忘录角色作为‘备忘发起角色’的一个私有内部类。好处就不详细解释了,看看代码就明白了。下面的代码是一个完整的备忘录模式的程序。它便采用了第二种方法来实现备忘录模式。还有一点值得指出的是,在下面的代码中,对于客户程序来说‘备忘录管理者角色’是不可见的,这样简化了客户程序使用备忘录模式的难度。下面采用‘备忘发起角色’来调用访问‘备忘录管理者角色’,也可以参考外观模式在客户程序与备忘录角色之间添加一个外观角色。”
classOriginator{
//这个是要保存的状态
privateintstate=90;
//保持一个“备忘录管理者角色”的对象
privateCaretakerc=newCaretaker();
//读取备忘录角色以恢复以前的状态
publicvoidsetMemento(){
Mementomemento=(Memento)c.getMemento();
state=memento.getState();
System.out.println(“thestateis”+state+“now”);
}
//创建一个备忘录角色,并将当前状态属性存入,托给“备忘录管理者角色”存放。
publicvoidcreateMemento(){
c.saveMemento(newMemento(state));
}
//thisisotherbusinessmethods……
//theymaybemodifytheattributestate
publicvoidmodifyState4Test(intm){
state=m;
System.out.println(“thestateis”+state+“now”);
}
//作为私有内部类的备忘录角色,它实现了窄接口,可以看到在第二种方法中宽接口已经不再需要
//注意:里面的属性和方法都是私有的
privateclassMementoimplementsMementoIF{
privateintstate;
privateMemento(intstate){
this.state=state;
}
privateintgetState(){
returnstate;
}
}
}
//测试代码——客户程序
publicclassTestInnerClass{
publicstaticvoidmain(String[]args){
Originatoro=newOriginator();
o.createMemento();
o.modifyState4Test(80);
o.setMemento();
}
}
//窄接口
interfaceMementoIF{}
//“备忘录管理者角色”
classCaretaker{
privateMementoIFm;
publicvoidsaveMemento(MementoIFm){
this.m=m;
}
publicMementoIFgetMemento(){
returnm;
}
}
大B:“第三种方式是不太推荐使用的:使用clone方法来简化备忘录模式。由于Java提供了clone机制,这使得复制一个对象变得轻松起来。使用了clone机制的备忘录模式,备忘录角色基本可以省略了,而且可以很好的保持对象的封装。但是在为你的类实现clone方法时要慎重!在上面的代码中,简单的模拟了备忘录模式的整个流程。在实际应用中,往往需要保存大量‘备忘发起角色’的历史状态。这时就要对‘备忘录管理者角色’进行改造,最简单的方式就是采用容器来按照顺序存放备忘录角色。这样就可以很好的实现undo、redo功能了。”