备忘录(Memento Pattern)模式 【行为模式第一篇】
备忘录(Memento Pattern)模式
备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化
存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。
常见的软件系统往往不止存储一个状态,而是需要存储多个状态。这些状态常常是一个对象历史发展的不同阶段的快照,存储这些快照的备忘录对象
叫做此对象的历史,某一个快照所处的位置叫做检查点。
备忘录角色:
备忘录角色有如下的责任。
1、将发起人(Originator)对象的内部状态存储起来,备忘录可以根据发起人对象的判断来决定存储多少
发起人(Originator)对象的内部状态。
2、备忘录可以保护其内容不被发起人对象之外的任何对象所读取。备忘录有两个等效的接口:
1、窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄
接(narrow interface),这个窄接口只允许它把备忘录对象传给其他的对象;
2、宽接口:与负责人对象看到的窄接口相反的是,发起人对象可以看到一个宽接口(wide interface),
这个宽接口允许它读取所有的数据,以便根据数据恢复这个发起人对象的内部状态。853P
发起人角色:
发起人角色有如下责任:
1、创建一个含有当前的内部状态的备忘录对象。
2、使用备忘录对象存储其内部状态。
负责人角色:
负责人角色有如下的责任:
1、负责保存备忘录对象
2、不检查备忘录对象的内容。
宽接口和白箱:发起人角色public class Originator{private String state;//工厂方法,返还一个新的备忘录对象public Memento createMemento(){return new Memento(state);}//将发起人恢复到备忘录对象所记载的状态public void restoreMemento(Memento memento){this.state = memento.getState();}//状态的取值方法public String getState(){return this.state;}//状态的赋值方法public void setState(String state){this.state = state;System.out.println("Current state = " + this.state);}}备忘录模式要求备忘录对象提供两个不同的接口:一个宽接口提供给发起人对象,另一个窄接口提供给所有其他的对象,包括负责人对象。宽接口允许发起人读取到所有的数据;窄接口只允许它把备忘录对象传给其他的对象而看不到内部的数据。//备忘录角色public class Memento{private String state;public Memento(String state){this.state = state;}public String getState(){return this.state;}public void setState(String state){this.state = state;}}负责人角色负责保存备忘录对象,但是从不修改(甚至不查看)备忘录对象的内容(一个更好的实现是负责人对象根本无法从备忘录对象中读取个修改其内容)//负责人角色public class Caretaker{private Memento memento;//备忘录的取值方法public Memento retrieveMemento(){return this.memento;}//备忘录的赋值方法public void saveMemento(Memento memento){this.memento = memento;}}//客户端public class Client{private static Originator o = new Originator();private static Caretaker c= new Caretaker();private static void main(String[] args){//该负责人对象的状态o.setState("On");//创建备忘录对象,并将发起人对象的状态存储起来c.saveMemento(o.createMemento());//修改发起人对象的状态o.setState("Off");//恢复发起人对象的状态o.restoreMemento(c.retrieveMemento());}}首先将发起人对象的状态设置成“On”(或者任何有效状态),并且创建一个备忘录对象将这个状态存储起来;然后将发起人对象的状态改成“Off”(或者任何状态);最后又将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态(或者先前所存储的任何状态)备忘录系统运行的时序是这样的:(1)将发起人对象的状态设置成“On”。(2)调用发起人角色的createMemento()方法,创建一个备忘录对象将这个状态存储起来。(3)将备忘录对象存储到负责人对象中去。备忘录系统恢复的时序是这样的:(1)将发起人对象的状态设置成“Off”;(2)将备忘录对象从负责人对象中取出;(3)将发起人对象恢复到备忘录对象所存储起来的状态,“On”状态。白箱实现的优缺点白箱实现的一个明显的好处是比较简单,因此常常用做教学目的。白箱实现的一个明显的缺点是破坏对发起人状态的封装。窄接口或者黑箱实现//发起人角色public class Originator{private String state;public Originator(){}//工厂方法,返还一个新的备忘录对象public MementoIF createMemento(){return new Memento(this.state);}//将发起人恢复到备忘录对象记录的状态public void restoreMemento(MementoIF memento){Memento aMemento = (Memento)memento;this.setState(aMemento.getState());}public String getState(){return this.state;}public void setState(){this.state = state;System.out.println("state = " + state);}protected class Memento implements MementoIF{private String savedState;private Mememto(String someState){savedState = someState;}private void setState(String someState){savedState = someState;}private String getState(){return savedState;}}}public interface MementoIF{}public class Caretaker{private MementoIF memento;public MementoIF retrieveMemento(){return this.memento;}public void saveMemento(MementoIF memento){this.memento = memento;}}public class Client{private static Originator o = new Originator();private static Caretaker c = new Caretaker();public static void main(String args[]){//改变负责人对象的状态o.setState("On");//创建备忘录对象,并将发起人对象的状态存储起来c.saveMemento(o.createMemento());//修改发起人对象的状态o.setState("Off");//恢复发起人对象的状态o.restoreMemento(c.retrieveMemento());}}黑箱实现运行时的时序为;(1)将发起人对象的状态设置成“On”。(2)调用发起人角色的 createMemento()方法,创建一个备忘录对象将这个状态存储起来。(3)将备忘录对象存储到负责人对象中去。由于负责人对象拿到的仅是 MementoIF类型,因此无法读出备忘录内部的状态。恢复时的时序为:(1)将发起人对象的状态设置成“Off”;(2)将备忘录对象从负责人对象中取出。注意此时仅能得到 MementoIF接口,因此无法读出此对象的内部状态(3)将发起人对象的状态恢复成备忘录对象所存储起来的状态,,由于发起人对象的内部类Memento实现了MementoIF接口 这个内部类是传入的备忘录对象的真实类型,因此发起人对象可以利用内部类Memento 的私有 接口读出此对象的内部状态 存储多个状态的备忘录模式://发起人角色import java.util.Vector;import java.util.Enumeration;public class Originator{private Vector states;private int index;public Originator(){states = new Vector();index = 0;}public Memento createMementor(){return new Mementor(states,index);}public void restoreMementor(Mementor memento){states = memento.getStates();index = memento.getIndex();}public void setState(String state){this.states.addElement(state);index ++;}//辅助方法,打印出所有的状态public void printStates(){System.out.println("Total number of states: " + index);for(Enumeration e = states.elements();e.hasMoreElements();){system.out.println(e.nextElement());}}} //备忘录角色import java.util.Vector;public class Memento{private Vector states;private int index;public Memento(Vector states,int index){this.states = (Vector)states.clone();this.index = index;}//状态取值方法Vector getStates(){return states;}//检查点取值方法int getIndex(){return this.index;}}******************备忘录的构造子克隆了传入的states,然后将克隆存入到备忘录对象内部,这是一个重要的细节,因为不这样的话,将会 将会造成客户端和备忘录对象持有对同一个Vector对象的引用,也可以同时修改这个Vector对象,会造成系统崩溃。 //负责人角色import java.util.Vector;public class Caretaker{private Originator o;private Vector mementos = new Vector();private int current;public Caretaker(Originator o){this.o = o;current = 0;}public int createMemento(){Memento memento = o.createMemento();mementos.addElement(memento);return current ++;}//将发起人恢复到某个检查点public void restoreMemento(int index){Memento memento = (Memento)mementos.elementAt(index);o.restoreMemento(memento);}//某个检查点删除public void removeMemento(int index){mementos.removeElementAt(index);}}//客户端public class Client{private static Originator o = new Originator();private static Caretaker c = new Caretaker(o);public static void main(String[] args){//改变状态o.setState("state 0");//建立一个检查点c.createMemento();//改变状态o.setState("state 1");c.createMemento();o.setState("state 2");c.createMemento();o.setState("state 3");c.createMemento();o.setState("state 4");c.createMemento();o.printStates();//恢复到第二个检查点System.out.println("Restoring to 2");c.restoreMemento(2);o.printStates();System.out.println("Restoring to 0");c.restoreMemento(0);o.printStates();System.out.println("Restoring to 3");c.restoreMemento(3);o.printStates();}}自述历史模式(备忘录模式的一个变种)://窄接口public interface MementoIF{}//发起人角色public class Originator{public String state;public Originator(){}public void changeState(String state){this.state = state;System.out.println("State has been changed to : " + state);}public Memento createMemento(){return new Memento(this);}public void restoreMemento(MementoIF memento){Memento m = (Memento)memento;changeState(m.state);}class Memento implements MementoIF{private String state;private String getState(){return state;}private Memento(Originator o){this.state = o.state;}}}//客户端public class Client{private static Originator o;private static MementoIF memento;public static void main(String args[]){o = new Originator();o.changeState("State 1");memento = o.createMemento();o.changeState("State 2");o.restoreMemento(memento);}}