狐言不胡言

导航

观世音甘泉活树的故事竟然是Java设计模式:备忘录模式

定义

备忘录模式是对象的行为型模式,备忘录对象是一个用来存储另外一个对象内部状态的快照的对象,备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化存储起来,从而可以使得在将来合适的时候把这个对象还原到存储起来的状态

意图

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态

主要解决问题

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态

何时使用

很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃

优缺点

优点:

  • 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这个时候使用备忘录模式,可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以保持封装的边界
  • 当发起人角色的状态改变时,有可能这个状态无效,这个时候就可以使用暂时存储起来的备忘录将状态复原

缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存

结构

在这里插入图片描述
涉及的角色:

  • 备忘录(Memento)角色:

    • 将发起人(Originator)对象的内部状态存储起来;备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态
    • 备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取,备忘录有两个等效的接口:
      • 窄接口:负责人(Caretaker)对象和其他除发起人对象之外的任何对象,看到的是备忘录的窄接口,这个接口只允许它把备忘录对象传给其他的对象
      • 宽接口:发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复发起人对象的内部状态
  • 发起人(Originator)角色:

    • 创建一个含有当前的内部状态的备忘录对象
    • 使用备忘录对象存储其内部状态
  • 负责人(Caretaker)角色:

    • 负责保存备忘录对象
    • 不检查备忘录对象的内容

白箱实现

将发起人角色的状态存储在一个大家都看的到的地方,因此是破坏封装性的
在这里插入图片描述
源码如下:

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("当前状态:" + 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 getMemento() {
        return this.memento;
    }

    /** 备忘录的赋值方法 */
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        //改变发起人对象的状态
        originator.setState("On");
        //创建备忘录对象,并将发起人对象的状态存储起来
        caretaker.setMemento(originator.createMemento());
        //修改发起人对象的状态
        originator.setState("Off");
        originator.restoreMemento(caretaker.getMemento());
        //恢复发起人对象的状态
        System.out.println("恢复状态:" + originator.getState());
    }
}

黑箱实现

将Memento类设成Originator类的内部类,在外部提供一个标识接口MementoIF给Caretaker类以及其他对象
在这里插入图片描述
源码如下:

public class Originator {

    private String state;

    public Originator() {
    }

    /** 返回一个新的备忘录对象 */
    public MementoIF createMemento() {
        return new Memento(this.state);
    }

    /** 将发起人恢复到备忘录对象所记录的状态 */
    public void restoreMemento(MementoIF memento) {
        Memento memento1 = (Memento) memento;
        this.state = memento1.getState();
    }

    /** 状态的取值方法 */
    public String getState() {
        return this.state;
    }

    /** 状态的赋值方法 */
    public void setState(String state) {
        this.state = state;
        System.out.println("当前状态:" + this.state);
    }

    /** 内部成员类,备忘录 */
    protected class Memento implements MementoIF {
        private String saveState;

        private Memento(String state) {
            this.saveState = state;
        }

        /** 状态的取值方法 */
        private String getState() {
            return this.saveState;
        }

        /** 状态的赋值方法 */
        private void setState(String state) {
            this.saveState = state;
        }
    }
}
public interface MementoIF {
}
public class Caretaker {

    private MementoIF memento;

    /** 备忘录的取值方法 */
    public MementoIF getMemento() {
        return this.memento;
    }

    /** 备忘录的赋值方法 */
    public void setMemento(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.setMemento(o.createMemento());
        //修改发起人对象的状态
        o.setState("Off");
        o.restoreMemento(c.getMemento());
        //恢复发起人对象的状态
        System.out.println("恢复状态:" + o.getState());
    }
}

多重检查点

存储多个状态,或者叫做有多个检查点

public class Originator {

    private Vector states;

    private int index;

    public Originator() {
        this.states = new Vector();
        this.index = 0;
    }

    /** 返回一个新的备忘录对象 */
    public Memento createMemento() {
        return new Memento(states, index);
    }

    /** 将发起人恢复到备忘录对象所记录的状态 */
    public void restoreMemento(Memento memento) {
        this.states = memento.getStates();
        this.index = memento.getIndex();
    }

    /** 状态的赋值方法 */
    public void setState(String state) {
        this.states.addElement(state);
        index++;
    }

    /** 打印出所有的状态 */
    public void printStates() {
        System.out.println("总的状态数量:" + index);
        for (Enumeration e = states.elements(); e.hasMoreElements();) {
            System.out.println(e.nextElement());
        }
    }
}
public class Memento {

    private Vector states;

    private int index;

    public Memento(Vector states, int index) {
        this.states = (Vector) states.clone();
        this.index = index;
    }

    /** 状态的取值方法 */
    public Vector getStates() {
        return states;
    }

    /** 检查点指数的取值方法 */
    public int getIndex() {
        return index;
    }
}
public class Caretaker {

    private Originator originator;
    private Vector vector = new Vector();
    private int current;

    public Caretaker(Originator originator) {
        this.originator = originator;
        this.current = 0;
    }

    /** 创建一个新的检查点 */
    public int createMemento() {
        Memento memento = originator.createMemento();
        vector.addElement(memento);
        return current++;
    }

    /** 将发起人恢复到某个检查点 */
    public void restoreMemento(int index) {
        Memento memento = (Memento) vector.elementAt(index);
        originator.restoreMemento(memento);
    }

    /** 将某个检查点删除 */
    public void removeMemento(int index) {
        vector.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.printStates();
        //恢复到第1个检查点
        System.out.println("恢复到第1个检查点");
        c.restoreMemento(1);
        o.printStates();
        //恢复到第3个检查点
        System.out.println("恢复到第2个检查点");
        c.restoreMemento(2);
        o.printStates();
    }
}

在这里插入图片描述

观世音甘泉活树的故事

孙大圣保护唐僧西行,路过万寿山五庄观,与道童发生口角,一时发怒,把人参果树推倒;大圣只好请观世音菩萨救活人参果树

在这里,果树的状态保存在观世音的甘露之中,菩萨可以从甘露中把果树的状态恢复过来,果树是发起人角色,甘露是备忘录角色,菩萨是负责人角色

public class SweetSpringWater {

    private String fruiterState;

    public SweetSpringWater(String fruiterState) {
        this.fruiterState = fruiterState;
    }

    /** 获取果树的状态 */
    public String getFruiterState() {
        return fruiterState;
    }

    /** 设置果树的状态 */
    public void setFruiterState(String fruiterState) {
        this.fruiterState = fruiterState;
    }
}
public class Fruiter {

    private String fruiterState;

    /** 返回一个新的备忘录对象 */
    public SweetSpringWater createMemento() {
        return new SweetSpringWater(fruiterState);
    }

    /** 将发起人恢复到备忘录对象所记录的状态 */
    public void restoreSweetSpringWater(SweetSpringWater springWater) {
        this.fruiterState = springWater.getFruiterState();
    }

    /** 果树状态的取值方法 */
    public String getState() {
        return this.fruiterState;
    }

    /** 果树状态态的赋值方法 */
    public void setState(String fruiterState) {
        this.fruiterState = fruiterState;
        System.out.println("当前果树状态:" + this.fruiterState);
    }
}
public class Goddess {

    private SweetSpringWater sweetSpringWater;

    /** 备忘录的取值方法 */
    public SweetSpringWater getSweetSpringWater() {
        return this.sweetSpringWater;
    }

    /** 备忘录的赋值方法 */
    public void setMemento(SweetSpringWater sweetSpringWater) {
        this.sweetSpringWater = sweetSpringWater;
    }
}
public class Client {
    public static void main(String[] args) {
        Fruiter f = new Fruiter();
        Goddess g = new Goddess();
        //改变发起人对象的状态
        f.setState("果树被孙悟空推倒了");
        //创建备忘录对象,并将发起人对象的状态存储起来
        g.setMemento(f.createMemento());
        //修改发起人对象的状态
        f.setState("观世音用甘泉恢复果树状态");
        //恢复发起人对象的状态
        System.out.println("恢复状态:" + f.getState());
    }
}

在这里插入图片描述

posted on 2021-04-17 10:59  狐言不胡言  阅读(80)  评论(0编辑  收藏  举报