设计模式之备忘录模式Memento _阿- 备忘录模式 应用场景

简述

备忘录模式的用意是在不破坏封装性的条件下,将对象的状态存储起来,从而在未来合适的时候将对象的状态恢复到从前(某个检查点)。

角色

1.备忘录(Memento)角色

1)将发起人对象的内容状态存储起来。备忘录可以根据发起人对象的判断来决定存储多少发起人对象的内部状态。

2)备忘录可以保护其内容不被发起人对象之外的任何对象所读取。

3)备忘录有两个等效的接口:

窄接口(narrowinterface):负责人对象看到的是备忘录的窄接口,这个窄接口只允许它把备忘录对象传给其他的对象;

宽接口(wideinterface):与负责人对象看到的窄接口相反的是,发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态。

2.发起人(Originator)角色

1)创建一个含有当前内部状态的备忘录对象。

2)使用备忘录对象存储其内部状态。

3.负责人(Caretaker)角色

1)负责保存备忘录对象。

2)不检查备忘录对象的内容。

源代码

版本1.“白箱”备忘录模式的实现

Java中,实现“宽”和“窄”两个接口并不容易,如果暂时忽略两个接口的区别,仅为备忘录角色提供一个宽接口的话,备忘录的内部存储状态就对所有对象公开,这就是“白箱实现”。

“白箱”实现破坏了封装性,但是通过程序员自律,可以方便地实现备忘录模式。

“白箱”备忘录模式的类图如下:




设计模式之备忘录模式(Memento)_阿- 备忘录模式 应用场景

“白箱”备忘录模式的Java实现如下:

package备忘录模式;

publicclassMemento{

privateStringstate;

publicMemento(Stringstate){

this.state=state;

}

publicStringgetState(){

returnthis.state;

}

publicvoidsetState(Stringstate){

this.state=state;

}

}

package备忘录模式;

publicclassOriginator{

privateStringstate;

//工厂方法,返回一个新的备忘录对象

publicMementocreateMemento(){

returnnewMemento(state);

}

//将发起人恢复到备忘录对象所记载的状态

publicvoidrestoreMemento(Mementomemento){

this.state=memento.getState();

}

publicStringgetState(){

System.out.println("Currentstate:"+state);

returnthis.state;

}

publicvoidsetState(Stringstate){

this.state=state;

}

}

package备忘录模式;

publicclassCaretaker{

privateMementomemento;

publicMementoretrieveMemento(){

returnthis.memento;

}

publicvoidsaveMemento(Mementomemento){

this.memento=memento;

}

}

package备忘录模式;

publicclassClient{

publicstaticvoidmain(String[]args){

Originatoro=newOriginator();

Caretakerc=newCaretaker();

//改变发起人的状态

o.setState("on");

o.getState();

//创建备忘录对象,并将发起人对象的状态存储起来

c.saveMemento(o.createMemento());

//再次改变发起人对象的状态

o.setState("off");

o.getState();

//恢复发起人对象的状态

o.restoreMemento(c.retrieveMemento());

o.getState();

}

}

输出:

Currentstate:on

Currentstate:off

Currentstate:on

版本2.“黑箱”备忘录模式的实现

将Memento设成Originator类的内部类;

将Memento的方法全部设成私有方法,这样只有它自己和发起人Originator可以调用;

在外部提供一个标识接口MementoIF给Caretaker以及其他对象,标识接口MementoIF没有提供任何方法,因此对外部来说Memento对象的内容都是不可见的。具体源代码见版本3中多个检查点的实现。

版本3.实现多个检查点的备忘录模式。

与版本1相比:

第一,版本3使用“黑箱”备忘录模式实现。

第二,版本3增强了负责人的功能,客户端不操作发起人角色进行备忘录的创建和状态的恢复,而只需要调用负责人即可。因此负责人角色要持有一个发起人角色的引用。

第三,版本3有多个检查点。

版本3的类图如下:


版本3源代码如下:

package备忘录模式;

//标识接口(窄接口)

publicinterfaceMementoIF{

}

package备忘录模式;

importjava.util.Vector;

publicclassOriginator{

privateVector<Object>states;

privateintindex;

publicOriginator(){

states=newVector<Object>();

index=0;

}

//工厂方法,返回一个新的备忘录对象

publicMementoIFcreateMemento(){

returnnewMemento(this.states,index);

}

//将发起人恢复到备忘录对象所记载的状态

publicvoidrestoreMemento(MementoIFmemento){

states=((Memento)memento).getStates();

index=((Memento)memento).getIndex();

}

//状态的赋值方法

publicvoidsetState(Objectstate){

this.states.addElement(state);

index++;

}

//辅助方法,打印出所有状态

publicvoidprintStates(){

System.out.println("Totalnumberofstates:"+index);

for(Objecto:states){

System.out.println(o.toString());

}

}

//内部类

protectedclassMementoimplementsMementoIF{

privateVector<Object>saveStates;

privateintsaveIndex;

@SuppressWarnings("unchecked")

//_states一定是Vector<Object类型的变量,复制后也一定是Vector<Object的变量

privateMemento(Vector<Object>_states,int_index){

//保存客户端传来的状态对象的拷贝,否则客户端的修改会影响到保存的状态。

saveStates=(Vector<Object>)_states.clone();

saveIndex=_index;

}

privateVector<Object>getStates(){

returnsaveStates;

}

privateintgetIndex(){

returnsaveIndex;

}

}

}

package备忘录模式;

importjava.util.Vector;

publicclassCaretaker{

privateOriginatoro;

privateVector<MementoIF>mementos=newVector<MementoIF>();

privateintcurrentIndex;

publicCaretaker(Originatoro){

this.o=o;

currentIndex=0;

}

//创建一个新的检查点

publicvoidcreateMemento(){

mementos.addElement(o.createMemento());

currentIndex++;

}

//将发起人恢复到某个检查点

publicvoidreStoreMemento(intindex){

o.restoreMemento(mementos.elementAt(index));

}

//删除某个检查点

publicvoidremoveMemento(intindex){

mementos.removeElementAt(index);

}

}

package备忘录模式;

publicclassClient{

publicstaticvoidmain(String[]args){

Originatoro=newOriginator();

Caretakerc=newCaretaker(o);

//改变发起人的状态

o.setState("state0");

//创建一个检查点

c.createMemento();

o.setState("state1");

c.createMemento();

o.setState("state2");

c.createMemento();

o.setState("state3");

c.createMemento();

o.setState("state4");

c.createMemento();

//打印出所有状态

o.printStates();

//恢复到第3个检查点

System.out.println("Restoringto3");

c.reStoreMemento(3);

o.printStates();

//恢复到第0个检查点

System.out.println("Restoringto0");

c.reStoreMemento(0);

o.printStates();

//恢复到第4个检查点

System.out.println("Restoringto4");

c.reStoreMemento(4);

o.printStates();

}

}

输出:

Totalnumberofstates:5

state0

state1

state2

state3

state4

Restoringto3

Totalnumberofstates:4

state0

state1

state2

state3

Restoringto0

Totalnumberofstates:1

state0

Restoringto4

Totalnumberofstates:5

state0

state1

state2

state3

state4

跟版本1相比,负责人角色除了负责保存状态之外,还负责发起人状态的恢复,功能增强了。

注意

1.以上的内容基本上都可以从阎宏的《Java与模式》找到,我只是“取其精华并整理之”。完成以上的工作后,我发现有些东西需要补充一下,以免有误导。

2.“黑箱”备忘录的实现中,将Memento类做成Originator的内部类,并将其方法全部设置成private,其实这样一般来说就已经足够了,不需要再使用窄接口MementoIF。因为这样做的话外部拿到Memento类的实例,由于其方法都是private的,所以该方法只有Originator类可以调用,其它类是调用不了的,也就无法修改其中的内容。

3.那么窄接口什么时候使用呢,我觉得应该是这样,如果Memento类因为某些原因不能做成内部类,那么就应该定义两个接口,一个WideMemento,一个NarrowMemento(一般没有定义任何方法),前者供Originator类使用,后者供其它类使用。这样的缺点就是,外部只要将得到的实例强制转化为WideMemento类型,同样可以访问到Memento类的内容。

4.如果要继承Originator类并且不改变Memento类的代码,那么Memento类的方法应该设置成默认属性(packageaccess),而不是private。

相关模式

命令模式:命令模式中使用备忘录模式来存储可撤销的操作的状态。

  

爱华网本文地址 » http://www.413yy.cn/a/25101012/119104.html

更多阅读

浅析Producer-Consumer设计模式 producer consumer

我气死了都!终于登上博客了!什么破网络!本来都不打算写了!不过这个问题已经总结了有一段时间了,就是生产者消费者模式,我是用professor上课的代码来分析的。下面我就贴上代码吧,在代码中有注释,就是对生产者和消费者的分析吧。我要抓紧时间,

设计模式的UML图(转) 工厂模式uml图

1.抽象工厂(Abstract Factory)模式意图:为特定的客户(或情况)提供特定系列的对象。2.类的适配器(Adapter)模式意图:将一个类的接口转换成客户希望的另外一个接口。3.对象的适配器(Adapter)模式意图:将一个类的接口转换成客户希望的

设计模式概论 设计学概论

设计模式概论1. 设计模式设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系

单一设计模式(Singleton) singleton模式 c

什么是Singleton模式?Sigleton模式的设计意图是:保证一个类只有一个对象实例,并提供一个访问对象实例的全局访问点。如果我们想实现一个全局范围可见的对象以替代麻烦缠身的全局变量,那么最好的做法就是将数据封装在一个特殊的类中。

DTC模式 设计模式

DTC模式文/红叶霜天DTC(direct tocustomer),即院外销售。一般指医药代表与医生沟通好,要求医生开具处方让顾客到指定的与药企合作的药房购买。一般由医药代表带领顾客到特定药房购买,这是源于美国的一种模式,在国外很普遍。市场前景:按

声明:《设计模式之备忘录模式Memento _阿- 备忘录模式 应用场景》为网友宁静的妩媚分享!如侵犯到您的合法权益请联系我们删除