• Java 设计模式系列(十八)备忘录模式(Memento)


    Java 设计模式系列(十八)备忘录模式(Memento)

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

    一、备忘录模式的结构

    图18-1 备忘录模式的结构

    备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。

    • 备忘录(Memento)角色

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

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

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

    * 窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄接口(narrow interface),这个窄接口只允许它把备忘录对象传给其他的对象。
    

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

    • 发起人(Originator)角色:

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

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

    • 负责人(Caretaker)角色

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

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

    源代码

    (1) Memento 接口

    /**
     * 备忘录的窄接口,没有任何方法定义
     */
    public interface Memento {
    
    }
    

    (2) Originator

    /**
     * 原发器对象
     */
    public class Originator implements Memento {
        /**
         * 示意,表示原发器的状态
         */
        private String state = "";
    
        /**
         * 创建保存原发器对象的状态的备忘录对象
         * @return 创建好的备忘录对象
         */
        public Memento createMemento() {
            return new MementoImpl(state);
        }
    
        /**
         * 重新设置原发器对象的状态,让其回到备忘录对象记录的状态
         * @param memento 记录有原发器状态的备忘录对象
         */
        public void retriveMemento(Memento memento) {
            MementoImpl mementoImpl = (MementoImpl)memento;
            this.state = mementoImpl.getState();
        }
    
        /**
         * 真正的备忘录对象,实现备忘录窄接口
         * 实现成私有的内部类,不让外部访问
         */
        private static class MementoImpl implements Memento{
            /**
             * 示意,表示需要保存的状态
             */
            private String state = "";
            public MementoImpl(String state){
                this.state = state;
            }
            public String getState() {
                return state;
            }
        }
    }
    

    (3) Caretaker

    /**
     * 负责保存备忘录的对象
     */
    public class Caretaker {
        /**
         * 记录被保存的备忘录对象
         */
        private Memento memento = null;
        /**
         * 保存备忘录对象
         * @param memento 被保存的备忘录对象
         */
        public void saveMemento(Memento memento){
            this.memento = memento;
        }
        /**
         * 获取被保存的备忘录对象
         * @return 被保存的备忘录对象
         */
        public Memento retriveMemento(){
            return this.memento;
        }
    }
    

    (4) 测试

    public class Main {
    
        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.restoreMemento(c.retrieveMemento());
    
            System.out.println(o.getState());
        }
    }
    

    二、多备份点

    图18-2 多备份点

    (1) Memento

    public interface Memento {
        int getIndex();
    }
    

    (2) Originator

    public class Originator implements Memento {
    
        //检查点指数
        private int index;
    
        /** 示意,表示原发器的状态 */
        private String state = "";
    
        /** 创建保存原发器对象的状态的备忘录对象 */
        public Memento createMemento() {
            return new MementoImpl(state, index);
        }
    
        /** 重新设置原发器对象的状态,让其回到备忘录对象记录的状态 */
        public void restoreMemento(Memento memento) {
            MementoImpl mementoImpl = (MementoImpl)memento;
            this.state = mementoImpl.getState();
            index = memento.getIndex();
        }
    
        // Ingore getter/setter
    
        /**
         * 真正的备忘录对象,实现备忘录窄接口
         * 实现成私有的内部类,不让外部访问
         */
        private static class MementoImpl implements Memento {
            private int index;
    
            /** 示意,表示需要保存的状态*/
            private String state = "";
            public MementoImpl(String state, int index){
                this.state = state;
                this.index = index;
            }
            
            // Ingore getter/setter
        }
    }
    

    (3) Caretaker

    public class Caretaker {
        /** 记录被保存的备忘录对象 */
        private List<Memento> mementos = new ArrayList<>();
        private int current;
    
        /** 保存备忘录对象 */
        public int saveMemento(Memento memento){
            this.mementos.add(memento);
            return current++;
        }
    
        /** 获取被保存的备忘录对象 */
        public Memento retrieveMemento(int index){
            return this.mementos.get(index);
        }
    }
    

    (4) 测试

    public class Client {
    
        public static void main(String[] args) {
    
            Originator o = new Originator();
            Caretaker c = new Caretaker();
            //改变负责人对象的状态
            o.setState("On");
            //创建备忘录对象,并将发起人对象的状态储存起来
            c.saveMemento(o.createMemento());
            //修改发起人的状态
            o.setState("Off");
            c.saveMemento(o.createMemento());
            //恢复发起人对象的状态
            o.restoreMemento(c.retrieveMemento(1));
    
            System.out.println(o.getState());
        }
    }
    

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    在 SVG 中添加交互性
    大型Web2.0站点构建技术初探 (转)
    鼠标右键右键菜单
    用SVG技术实现动态图形输出的嵌入式Web服务
    使用脚本动态操作 SVG 文档
    GDI+技术的坐标解决方案
    一个项目的粗略流程
    xml矢量图:svg的viewBox和vml的coordsize决定的虚坐标系简说
    用VML画图(一些基本的矢量图)
    列出本地可用字体
  • 原文地址:https://www.cnblogs.com/binarylei/p/9017735.html
Copyright © 2020-2023  润新知