• 设计模式之备忘录模式


    备忘录模式

    概述

    备忘录模式是一种软件设计模式:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

    这种设计模式无论在生活中还是开发中都是非常常见的,比如不存在的后悔药等,而在开发中比如ctrl+z回退、Photoshop的历史记录等

    示例程序

    而对于我们开发者比较常见的一个功能在于发布程序版本的,有时候紧急部署一个新的版本却发现不能用,我们可以迅速的回滚到上个版本。在示例程序中我们模拟在发布上线的过程中记录线上配置文件用于紧急回滚

    名称说明
    ConfigFile配置文件类,此类不属于备忘录模式的核心
    ConfigMemento备忘录类,此类管理ConfigFile
    ConfigOriginator记录者类,此类拥有生成ConfigMemento的方法
    Admin管理员类

    代码实现

    ConfigFile

    @Data
    @AllArgsConstructor
    public class ConfigFile {
        private String versionNo; // 版本号
        private String content;   // 内容
        private Date dateTime;    // 时间
        private String operator;  // 操作人
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ConfigMemento

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class ConfigMemento {
        private ConfigFile configFile;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ConfigOriginator

    saveMemento保存包网路的时候会创建一个备忘录信息,并返回去,交给管理者处理

    getMemento获取到之后并不是直接返回,而是把备忘录的信息交给现在的配置文件this.configFile

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class ConfigOriginator {
        private ConfigFile configFile;
    
        public ConfigMemento saveMemento(){
            return new ConfigMemento(configFile);
        }
    
        public void getMemento(ConfigMemento memento){
            this.configFile = memento.getConfigFile();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Admin

    public class Admin {
        private int cursorIdx = 0;
        private List<ConfigMemento> mementoList = new ArrayList<>();
        private Map<String, ConfigMemento> mementoMap = new ConcurrentHashMap<>();
    
        public void append(ConfigMemento memento){
            cursorIdx++;
            mementoList.add(memento);
            mementoMap.put(memento.getConfigFile().getVersionNo(),memento);
        }
    
        //回退一个版本
        public ConfigMemento undo(){
            if (--cursorIdx <= 0) {
                return mementoList.get(0);
            }
            return mementoList.get(cursorIdx);
        }
    
        //前进一个版本
        public ConfigMemento redo(){
            if (++cursorIdx > mementoMap.size()){
                return mementoList.get(mementoMap.size() - 1);
            }
            return mementoList.get(cursorIdx);
        }
    
        //获取某一个版本
        public ConfigMemento get(String versionNo){
            return mementoMap.get(versionNo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    Test

    @SpringBootTest
    class Practice2000ApplicationTests {
        @Test
        void contextLoads() {
            Admin admin = new Admin();
            ConfigOriginator configOriginator = new ConfigOriginator();
            configOriginator.setConfigFile(new ConfigFile("yellowstar0.0.1", "第一次", new Date(), "yellowstar"));
            admin.append(configOriginator.saveMemento());
            configOriginator.setConfigFile(new ConfigFile("yellowstar0.0.2", "第二次", new Date(), "yellowstar"));
            admin.append(configOriginator.saveMemento());
            configOriginator.setConfigFile(new ConfigFile("yellowstar0.0.3", "第三次", new Date(), "yellowstar"));
            admin.append(configOriginator.saveMemento());
            configOriginator.setConfigFile(new ConfigFile("yellowstar0.0.4", "第四次", new Date(), "yellowstar"));
            admin.append(configOriginator.saveMemento());
    
            configOriginator.getMemento(admin.undo());
            System.out.println("回滚一次" + configOriginator.getConfigFile());
    
            configOriginator.getMemento(admin.undo());
            System.out.println("再回滚一次" + configOriginator.getConfigFile());
    
            configOriginator.getMemento(admin.redo());
            System.out.println("前进一次" + configOriginator.getConfigFile());
    
            configOriginator.getMemento(admin.get("yellowstar0.0.1"));
            System.out.println("到达指定版本" + configOriginator.getConfigFile());
        }
    }
    
    //结果
    回滚一次ConfigFile(versionNo=yellowstar0.0.4, content=第四次, dateTime=Wed Jun 22 14:48:51 CST 2022, operator=yellowstar)
    再回滚一次ConfigFile(versionNo=yellowstar0.0.3, content=第三次, dateTime=Wed Jun 22 14:48:51 CST 2022, operator=yellowstar)
    前进一次ConfigFile(versionNo=yellowstar0.0.4, content=第四次, dateTime=Wed Jun 22 14:48:51 CST 2022, operator=yellowstar)
    到达指定版本ConfigFile(versionNo=yellowstar0.0.1, content=第一次, dateTime=Wed Jun 22 14:48:51 CST 2022, operator=yellowstar)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    总结

    备忘录模式是一种对象行为型模式,其主要优点如下

    • 提供一种可以恢复状态的机制,当用户需要时能够比较方便的将数据恢复到某个历史的状态
    • 实现了内部状态的封装,除了创建它的发起人之外,其他对象都不能够访问这些状态信息

    缺点也很明显

    • 资源消耗大,如果要保存的内部状态信息过多,将会占用比较大的内存资源
  • 相关阅读:
    【Linux】自动化构建工具--make/Makefile&&调试器--gdb的使用
    论坛介绍 | COSCon'23 开源治理(G)
    MySQL-数据库的设计范式
    荧光染料AF488 carboxylic acid,AF488 COOH/ACID/羧酸羧基
    【JavaSE】集合专项练习篇(附源码)
    Qt 中设置窗体(QWidget)透明度的几种方法
    C++ 制作动态链接库.dll及.dll使用
    生信步骤|kmc+genomescope进行基因组调查
    Oracle-通过(RESTORE/RECOVER FROM SERVICE)方式搭建DataGuard
    GPT-4V:AI在医疗领域的应用
  • 原文地址:https://blog.csdn.net/Yellow_Star___/article/details/125410480