设计模式之备忘录模式详解

备忘录模式

文章目录

  • 备忘录模式
    • 一、什么是备忘录模式
    • 二、备忘录模式的角色组成
    • 三、备忘录模式的通用写法
    • 四、备忘录模式的业务应用举例
    • 五、备忘录模式的优缺点

一、什么是备忘录模式

备忘录模式(Memento Pattern)又称为快照模式(Snapshot Pattern),是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态,属于行为型模式

二、备忘录模式的角色组成

备忘录模式的通用类图:
设计模式之备忘录模式详解_第1张图片

发起人角色(Originator):负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能

备忘录角色(Memento):用于存储Originator的内部状态,且可以防止Originator以外的对象进行访问

备忘录管理员角色(Caretaker):负责存储,提供管理备忘录(Memento),无法对备忘录内容进行操作和访问

三、备忘录模式的通用写法

  1. 创建备忘录角色

    /**
     * 备忘录角色,存储发起人(Originator) 的内部状态
     *
     * @author zdp
     * @date 2022/9/24 9:55
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Memento {
    
        private String state;
    
    }
    
  2. 创建发起人角色

    /**
     * 发起人角色 自身状态需要被保存到备忘录角色中
     *
     * @author zdp
     * @date 2022/9/24 9:55
     */
    @Data
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class Originator {
    
        /**
         * 需要存储到备忘录角色的状态
         */
        private String state;
    
        /**
         * 将自身状态存档,保存到备忘录角色中
         *
         * @author zdp
         * @date   2022/9/24 10:11
         */
        public Memento createMemento() {
            return new Memento(this.state);
        }
    
        /**
         * 从备忘录角色中获取上一次存储的状态
         *
         * @author zdp
         * @date   2022/9/24 10:12
         */
        public void restoreMemento(Memento memento) {
            this.setState(memento.getState());
        }
    
    }
    
  3. 创建备忘录管理员角色,用于管理备忘录

    /**
     * 备忘录管理员角色,提供存储和获取备忘录角色的入口
     *
     * @author zdp
     * @date 2022/9/24 9:55
     */
    public class Caretaker {
    
        private Memento memento;
    
        /**
         * 获取上一次的备忘录角色中存储的状态
         *
         * @author zdp
         * @date   2022/9/24 10:09
         */
        public Memento getMemento() {
            return this.memento;
        }
    
        /**
         * 存储状态到备忘录角色
         *
         * @author zdp
         * @date   2022/9/24 10:09
         */
        public void storeMemento(Memento memento) {
            this.memento = memento;
        }
    
    }
    
  4. 验证

    /**
     * 备忘录模式通用写法验证
     *
     * @author zdp
     * @date 2022/9/24 9:55
     */
    public class Test {
    
        public static void main(String[] args) {
            //发起人角色
            Originator originator = new Originator();
            //备忘录管理员角色
            Caretaker caretaker = new Caretaker();
    
            //发起人状态存档,存到备忘录角色中
            originator.setState("originator state one ...");
            System.out.println("originator首次设置状态完成...." + originator.toString());
            caretaker.storeMemento(originator.createMemento());
            System.out.println("第一次存档完成...." + originator.toString());
    
            originator.setState("originator state two ...");
            System.out.println("originator二次设置状态完成...." + originator.toString());
            //发起人回退至上一次存储的状态
            originator.restoreMemento(caretaker.getMemento());
            System.out.println("第一次回退完成...." + originator.toString());
        }
    
    }
    

四、备忘录模式的业务应用举例

下面列举这么一个需求用备忘录模式来实现一下,在csdn中的编写文章的过程中,草稿箱中也会存储我们写文章的记录,当浏览器意外关闭的时候,文章也可以从草稿箱中恢复

  1. 创建发起人角色(编辑文章对象)

    /**
     * 发起人角色(编辑文章对象)
     *
     * @author zdp
     * @date 2022/9/24 16:55
     */
    @Data
    @Builder
    public class ArticleEditor {
    
        /**
         * 标题
         */
        private String title;
    
        /**
         * 内容
         */
        private String content;
    
        /**
         * 将编辑的文章转换为备忘录角色存档
         *
         * @author zdp
         * @date   2022/9/24 17:15
         */
        public Article saveToMemento(ArticleEditor editor){
            return Article.builder()
                    .title(editor.getTitle())
                    .content(editor.getContent())
                    .build();
        }
    
        /**
         * 将草稿箱中的文章恢复到编辑状态
         *
         * @author zdp
         * @date   2022/9/24 17:17
         */
        public ArticleEditor undoFromMemento(Article article){
            return ArticleEditor.builder()
                    .title(article.getTitle())
                    .content(article.getContent())
                    .build();
        }
    }
    
    
  2. 创建备忘录角色(文章)

    /**
     * 备忘录角色(文章)
     *
     * @author zdp
     * @date 2022/9/24 17:00
     */
    @Data
    @ToString
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class Article {
    
        /**
         * 标题
         */
        private String title;
    
        /**
         * 内容
         */
        private String content;
    
    }
    
  3. 创建备忘录管理角色(草稿箱)

    /**
     * 备忘录管理角色(草稿箱)
     *
     * @author zdp
     * @date 2022/9/24 16:56
     */
    public class DraftsBox {
    
        private Stack<Article> container = new Stack<>();
    
        /**
         * 存档
         * 
         * @author zdp
         * @date   2022/9/24 17:35
         */
        public void addMemento(Article article){
            container.push(article);
        }
    
        /**
         * 读取上一次存档
         * 
         * @author zdp
         * @date   2022/9/24 17:35
         */
        public Article getMemento(){
            return container.pop();
        }
    }
    
  4. 验证

    /**
     * 备忘录模式业务验证
     *
     * @author zdp
     * @date 2022/9/24 9:55
     */
    @Slf4j
    public class Test {
        public static void main(String[] args) {
            //草稿箱
            DraftsBox box = new DraftsBox();
    
            //第一次编辑的文章对象
            ArticleEditor firstEditor = ArticleEditor.builder()
                    .title("标题:第一次标题~")
                    .content("内容:第一次内容~")
                    .build();
            //将第一次的编辑文章对象转换为备忘录角色,存到备忘录管理器中
            Article firstArticle = firstEditor.saveToMemento(firstEditor);
            //首次存档
            box.addMemento(firstArticle);
            log.info("草稿箱完成首次存档,存档内容为: {}", JSONObject.toJSONString(firstArticle));
    
            //第二次编辑的文章对象
            ArticleEditor secondEditor = ArticleEditor.builder()
                    .title("标题:第二次标题~")
                    .content("内容:第二次内容~")
                    .build();
            log.info("第二次编辑完成 {} ,但未存档~ 此时浏览器意外关闭,从草稿箱回退至上一次编辑的内容 ~", JSONObject.toJSONString(secondEditor));
    
            //从草稿箱恢复至上一次存档记录
            Article lastTimeArticle = box.getMemento();
            ArticleEditor lastTimeEditor = secondEditor.undoFromMemento(lastTimeArticle);
            log.info("草稿箱回退成功,回退至上一次存档内容,内容为: {}", JSONObject.toJSONString(lastTimeEditor));
        }
    }
    

在这里插入图片描述

五、备忘录模式的优缺点

  • 优点
    • 备忘录模式隔离了状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节
    • 备忘录模式提供了状态回滚的功能
  • 缺点
    • 如果需要保存的状态过多时,每一次保存都会消耗很多内存

你可能感兴趣的:(设计模式,设计模式,备忘录模式,java)