zoukankan      html  css  js  c++  java
  • 设计之禅——备忘录模式

    引言

    备忘录模式是非常简单的一种模式,应用场景非常广泛,如编辑器的ctrl + z、数据库事务的回滚、游戏的存档等等都符合该模式的思想——备份(比较疑惑为什么叫备忘录模式,叫备份模式不是更贴切么?)。

    详解

    备忘录模式就是将一个对象的内部状态保存到对象的外部,这样,在将来的任一时间点都可以恢复到之前的状态,让我们有后悔药可以吃。它包含了发起人(originator)、备忘录(memento)、负责人(caretaker)三个角色:

    • 发起人:负责创建备份,将当前对象所需存储的状态保存到外部,并可以在需要时恢复备份。
    • 备忘录:负责存储对象的内部状态。
    • 负责人:用于保存备忘录以及将备忘录传递给其它对象,但不能直接访问操作备忘录对象的内部状态(保证封装性和安全性)。

    模式的结构和定义都非常简单,下面就实现一个文本编辑器的“撤销”功能。

    Coding

    首先是编辑器对象,也就会发起人角色:

    public class Editor {
    
        private String content;
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public Memento createMemento() {
            return new Memento(this.content);
        }
    
        public void undo(Memento memento) {
            this.content = memento.getContent();
        }
    }
    

    备忘录对象:

    public class Memento {
    
        private String content;
    
        public Memento(String content) {
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    }
    

    负责人,只提供保存和传递备忘录对象的方法,不能对备忘录内部状态进行修改(这是必须的,否则无法保证恢复的数据是最初的数据,备忘录模式还有什么意义?):

    public class Caretaker {
    
        private Stack<Memento> mementos = new Stack<>();
    
        public void savePoint(Memento memento) {
            mementos.push(memento);
        }
    
        public Memento getMemento() {
            return mementos.pop();
        }
    
    }
    

    最后我们来体验下这个强大的编辑器吧:

        public static void main(String[] args) {
            Editor editor = new Editor();
            editor.setContent("1");
            System.out.println("第一次修改内容:" + editor.getContent());
    
            // 编辑内容并保存
            Caretaker caretaker = new Caretaker();
            caretaker.savePoint(editor.createMemento());
            editor.setContent("2");
            System.out.println("第二次修改后内容:" + editor.getContent());
            caretaker.savePoint(editor.createMemento());
            editor.setContent("3");
            System.out.println("第三次次修改后内容:" + editor.getContent());
            caretaker.savePoint(editor.createMemento());
            editor.setContent("4");
            System.out.println("第四次次修改后内容:" + editor.getContent());
    
            editor.undo(caretaker.getMemento());
            System.out.println("第一次恢复后的内容:" + editor.getContent());
            editor.undo(caretaker.getMemento());
            System.out.println("第二次恢复后的内容:" + editor.getContent());
            editor.undo(caretaker.getMemento());
            System.out.println("第三次恢复后的内容:" + editor.getContent());
        }
    

    输出如下:

    第一次修改内容:1
    第二次修改后内容:2
    第三次次修改后内容:3
    第四次次修改后内容:4
    第一次恢复后的内容:3
    第二次恢复后的内容:2
    第三次恢复后的内容:1
    

    这样我们就实现了一个单状态的备忘录模式,但在实际应用中,业务场景会复杂很多,我们可能会需要保存很多的状态,应该如何做呢?读者们可以自行思考一下,这里我就不展开了

    总结

    备忘录模式给我们提供了“后悔药”,让我们在需要时可以随时反悔,但是当记录的状态非常多时,就会占用大量的资源,因此在使用时需要设置合理的上限。

  • 相关阅读:
    正则表达式的点星匹配
    好玩Python——PIL项目实训(四)
    mysql中正则表达式使用学习记录
    linux下每个目录文件的作用
    彻底搞懂Android文件存储---内部存储,外部存储以及各种存储路径解惑
    获取APP包名和ACtivity名的方法
    mysql 中 王数据表中插入中文字段报错:mysql> insert into a values(202,"王一"); ERROR 1366 (HY000): Incorrect string value: 'xE7x8Ex8BxE4xB8x80' for column 'tname' at row 1
    linux系统下安装mysql
    测试人员初步分析BUG原因--转载
    PC端通过ADB命令 无线向 andriod端发送文件
  • 原文地址:https://www.cnblogs.com/yewy/p/13111834.html
Copyright © 2011-2022 走看看