您的位置:首页 > 编程语言 > Java开发

Java设计模式——备忘录模式(Memento)

2015-05-17 18:58 543 查看
又名快照模式或者token模式

备忘录对象是一个用来存储另一个对象内部状态的快照(snapshot)的对象。备忘录模式用意是在不破坏封装的条件下,将下一个对象的状态捕捉(capture),并外部化(externalize),存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一起使用。

备忘录模式涉及的角色:备忘录角色、发起人角色、负责人角色

备忘录角色(Memento):

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

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

两个等效的接口

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

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

发起人角色(Originator):

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

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

负责人角色(Caretaker):

1、负责保存备忘录对象

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

一、备忘录模式的白箱实现

如下图所示,示意性的“白箱实现”




发起人利用新创建的备忘录对象将自己的内部状态存储起来,代码如下:

public class Originator {

 private String state;

 /**
  * 工厂方法,返还一个新的备忘录对象
  * factory method,return a new Memento Object
  * @author 付玉伟
  * @time 2015-5-9 下午07:10:13
  * @return
  */
 public Memento createMemento(){
  return new Memento();
 }

 /**
  * 将发起人恢复到备忘录对象所记载的状态
  * retrieve originator to status of storing in Memento
  * @author 付玉伟
  * @time 2015-5-9 下午07:11:45
  * @param memento
  */
 public void restoreMemento(Memento memento){
  this.state = memento.getState();
 }

 public String getState() {
  return state;
 }

 public void setState(String state) {
  this.state = state;
  System.out.println("current state is:"+this.state);
 }
}


下面是备忘录角色的源代码,备忘录对象将发起人对象传入状态存储起来。备忘录角色会根据发起人对象的判断类决定将发起人的内部状态的多少存储起来。

public class Memento {

 private String state;

 public Memento(String state){
  this.state = state;
 }

 public String getState() {
  return state;
 }

 public void setState(String state) {
  this.state = state;
 }
}


下面是负责人角色的源码

public class Caretaker {

 private Memento memento;

 /**
  * 备忘录的取值方法
  * get value of Memento
  * @author 付玉伟
  * @time 2015-5-9 下午07:21:34
  * @return
  */
 public Memento retrieveMemento(){
  return this.memento;
 }

 /**
  * 备忘录的赋值方法
  * set value of Memento
  * @author 付玉伟
  * @time 2015-5-9 下午07:22:41
  * @param memento
  */
 public void saveMemento(Memento 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) {
  // change status of originator
  o.setState("On");
  // create Memento Object and save status Of originator
  c.saveMemento(o.createMemento());
  // change status of originator
  o.setState("Off");
  // retrieve status of originator
  o.restoreMemento(c.retrieveMemento());
 }
}


白箱实现的时序图:




系统运行的时序是这样的:

1、将发起人对象状态设置为on

2、调用发起人角色的createMemento方法,创建一个备忘录对象,将这个状态存储起来

3、将备忘录对象存储到负责人对象中

将发起人对象恢复到备忘录对象所记录的状态的时序图如下:




将发起人对象恢复备忘录对象所记录的状态系统运行的时序:

1、将发起人对象状态设置为off

2、将备忘录对象从负责人对象中取出来

3、将发起人对象恢复到备忘录对象所存储的状态,即on

白箱实现的优缺点:

优点:简单

缺点:破坏对发起人状态的封装

二、备忘录模式的黑箱实现

使用内部类实现黑箱模式的的类图如下:




在Originator类中 定义了一个内部的Memento类,由于Memento类的全部接口都是私有的,因此只有他自己和发起人可以调用。负责人角色Caretaker类的源代码可以看到,负责人角色能够得到备忘录对象是以MementoIF为接口的,由于这个接口仅仅是一个标识接口,因此负责人角色不可能改变这个备忘录对象的内容。

源码如下:

public class Originator {
    private String state;

    public Originator(){}

    public MementoIF createMemento(){
        return new Memento(this.state);
    }

    /**
     * 将发起人恢复到备忘录记录的状态
     * @author 付玉伟
     * @time 2015-5-12 下午09:59:02
     * @param memento
     */
    public void resotreMemento(MementoIF memento){
        Memento aMemento = (Memento)memento;
        this.setState(aMemento.getState());
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }


protected class Memento implements MementoIF{
        private String savedState;

        Memento(String someState){
            this.savedState = someState;
        }
        public String getState() {
            return savedState;
        }
        public void setState(String someState) {
            this.savedState = someState;
        }

    }

}


public class Caretaker {
    private MementoIF memento;

    /**
     * 备忘录的取值方法
     * @author 付玉伟
     * @time 2015-5-12 下午10:04:51
     * @return
     */
    public MementoIF retrieveMemento(){
        return this.memento;
    }

    /**
     * 备忘录的赋值方法
     * @author 付玉伟
     * @time 2015-5-12 下午10:05:25
     * @param memento
     */
    public void saveMemento(MementoIF memento){
        this.memento = memento;
    }

}


public interface MementoIF {
}


public class Client {
    /**
     * @author 付玉伟
     * @time 2015-5-12 下午10:05:49
     * @param args
     */
    public static void main(String[] args) {
        Originator o = new Originator();
        Caretaker c = new Caretaker();
        // 改变负责人状态
        o.setState("on");
        // 创建备忘录对象,并将发起人状态存储起来
        c.saveMemento(o.createMemento());
        // 修改发起人对象的状态
        o.setState("off");
        // 恢复发起人的状态
        o.resotreMemento(c.retrieveMemento());
        System.out.println(o.getState());
    }
}


备忘录模式的应用

1、JDBC与数据库

在架构设计的时候都必须注意将商业逻辑与存储逻辑分割开来原因如下:

a.两者分开可以交给不同的设计师,便于系统维护

b.商业逻辑变化存储逻辑不一定变

c.存储逻辑变化商业逻辑不一定变

2、J2EE框架中备忘录模式的应用

Cookie、URL改写、HTML的隐藏表等

3、系统配置文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: