首页 > 其他分享 >行为型设计模式之备忘录模式

行为型设计模式之备忘录模式

时间:2022-09-28 16:34:41浏览次数:48  
标签:gitOriginator 代码 模式 备忘录 提交 设计模式 public codeMemento

备忘录模式

备忘录模式又称为快照模式或令牌模式,属于行为型模式。

它是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。简而言之:允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。

它提供一种类似“后悔药”的机制,通过存储系统各个历史状态的快照,使得可以在任一时刻将系统回滚到某一个历史状态。

在这里插入图片描述

应用场景

1.需要保存历史快照的场景

2.希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存具体内容

应用场景举例:代码版本控制,游戏存档功能,数据库的事务管理等

假如有一款编辑器应用程序,程序在执行任何操作前记录所有的对象状态, 并将其保存下来。 当用户此后需要撤销某个操作时, 程序将从历史记录中获取最近的快照, 然后使用它来恢复所有对象的状态。

在这里插入图片描述

优缺点

优点:

1.简化发起人实体类Originator职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节

2.提供状态回滚功能:给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。

缺点:

1.消耗资源:如果需要保存的状态过多时,每一次保存都会消耗很多内存。

主要角色

备忘录模式主要包含三种角色:

1.发起人角色(Originator)

负责创建一个备忘录,记录自身需要保存的状态;具备状态回滚功能。

2.备忘录角色(Memento)

用于存储Originator的内部状态,且可以防止Originator以外的对象进行访问。

3.备忘录管理员角色(Caretaker)

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

在这里插入图片描述

备忘录模式本质是从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memento)独立,且存储信息的实体交由管理类(Caretaker)管理,则可以通过为管理类扩展额外的功能对存储信息进行扩展操作。

备忘录模式的基本使用

创建发备忘录角色

@Data
public class Memento {
    private String state;

    public Memento(String state){
        this.state = state;
    }
}

创建发起人角色

@Data
public class Originator {
    /**
     * 内部状态
     */
    private String state;

    /**
     * 创建一个备忘录
     *
     * @return
     */
    public Memento createMemento() {
        return new Memento(this.state);
    }

    /**
     * 从备忘录恢复
     *
     * @param memento
     */
    public void restoreMemento(Memento memento) {
        this.setState(memento.getState());
    }
}

创建备忘录管理员角色

public class Caretaker {
    private Memento memento;

    public Memento getMemento() {
        return this.memento;
    }
    public void storeMemento(Memento memento) {
        this.memento = memento;
    }
}

客户端执行

    public static void main(String[] args) {
        // 创建发起人角色
        Originator originator = new Originator();
        // 创建备忘录管理员
        Caretaker caretaker = new Caretaker();
        // 设置存储状态
        originator.setState("A");
        // 存储发起人创建的备忘录
        caretaker.storeMemento(originator.createMemento());
        System.out.println("设置存储状态:" + originator.getState());

        // 设置存储状态
        originator.setState("B");
        System.out.println("更新存储状态:" + originator.getState());

        // 备忘录进行回滚
        originator.restoreMemento(caretaker.getMemento());
        System.out.println("回滚到设置的状态:" + originator.getState());
    }
设置存储状态:A
更新存储状态:B
回滚到设置的状态:A

使用备忘录模式实现代码版本控制

创建发备忘录角色

@Data
@ToString
public class CodeMemento {
    /**
     * 提交内容
     */
    private String content;
    /**
     * 提交备注
     */
    private String remark;

    public CodeMemento(String content, String remark) {
        this.content = content;
        this.remark = remark;
    }
}

创建发起人角色

@Data
@ToString
public class GitOriginator {
    /**
     * 提交内容
     */
    private String content;
    /**
     * 提交备注
     */
    private String remark;

    public GitOriginator(String content, String remark) {
        this.content = content;
        this.remark = remark;
    }

    /**
     * 提交代码
     *
     * @return
     */
    public CodeMemento saveToMemento() {
        CodeMemento codeMemento = new CodeMemento(this.content, this.remark);
        return codeMemento;
    }

    /**
     * 恢复代码
     *
     * @param codeMemento
     */
    public void undoFromMemento(CodeMemento codeMemento) {
        this.content = codeMemento.getContent();
        this.remark = codeMemento.getRemark();
    }
}

创建备忘录管理员角色

public class GitCaretaker {
    /**
     * 使用栈来存储备忘录,最新的备忘录排在栈顶
     */
    private final Stack<CodeMemento> STACK = new Stack<CodeMemento>();

    public CodeMemento getMemento(){
        // 移除栈顶的备忘录
        CodeMemento codeMemento = STACK.pop();
        return codeMemento;
    }

    public void addMemento(CodeMemento codeMemento){
        // 将备忘录压入栈顶
        STACK.push(codeMemento);
    }

}

客户端执行

    public static void main(String[] args) {
        System.out.println("--------------------第一次创建代码--------------------------------");
        // 创建一个备忘录管理者
        GitCaretaker gitCaretaker = new GitCaretaker();
        // 创建一个备忘录发起人
        GitOriginator gitOriginator = new GitOriginator("write code 1", "第一次提交代码备注");
        // 创建一个备忘录
        CodeMemento codeMemento = gitOriginator.saveToMemento();
        // 将备忘录压入栈顶
        gitCaretaker.addMemento(codeMemento);
        System.out.println("第一次提交代码完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());


        System.out.println("--------------------第二次修改代码--------------------------------");
        gitOriginator.setContent("write code 2");
        gitOriginator.setRemark("第二次提交代码备注");
        codeMemento = gitOriginator.saveToMemento();
        gitCaretaker.addMemento(codeMemento);
        System.out.println("第二次提交代码完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());


        System.out.println("--------------------第三次修改代码--------------------------------");
        gitOriginator.setContent("write code 3");
        System.out.println("第三次修改代码。代码:" + gitOriginator.getContent());


        System.out.println("--------------------在第三次修改代码基础上回退到第二次提交--------------------------------");
        codeMemento = gitCaretaker.getMemento();
        gitOriginator.undoFromMemento(codeMemento);
        System.out.println("回退到第二次提交完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());


        System.out.println("--------------------在第二次修改代码基础上回退到第一次提交--------------------------------");
        codeMemento = gitCaretaker.getMemento();
        gitOriginator.undoFromMemento(codeMemento);
        System.out.println("回退到第一次提交完成。代码:" + gitOriginator.getContent() + " 备注:" + gitOriginator.getRemark());
    }
--------------------第一次创建代码--------------------------------
第一次提交代码完成。代码:write code 1 备注:第一次提交代码备注
--------------------第二次修改代码--------------------------------
第二次提交代码完成。代码:write code 2 备注:第二次提交代码备注
--------------------第三次修改代码--------------------------------
第三次修改代码。代码:write code 3
--------------------在第三次修改代码基础上回退到第二次提交--------------------------------
回退到第二次提交完成。代码:write code 2 备注:第二次提交代码备注
--------------------在第二次修改代码基础上回退到第一次提交--------------------------------
回退到第一次提交完成。代码:write code 1 备注:第一次提交代码备注

标签:gitOriginator,代码,模式,备忘录,提交,设计模式,public,codeMemento
From: https://blog.51cto.com/chencoding/5717460

相关文章

  • 设计模式 -- Singleton(单例模式)
    单例模式(Singleton)保证一个类仅有一个实例,并提供一个该实例的全局访问点。在软件系统中,经常有这样一个特殊的类,必须保证它们在系统中只存在一个示例,才能确保他们的逻辑......
  • 设计模式 -- Flyweight(享元模式)
    享元模式(Flyweight)运用共享技术有效地支持大量的细粒度对象在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行是代价——主......
  • 设计模式(一)
    1设计模式概述1.1设计模式的定义与分类设计模式的定义Designpatternsaredescriptionsofcommunicatingobjectsandclassesthatarecustomizedtosolvea......
  • 何增耀--数据模型通用模式讲座录像
    何增耀--数据模型通用模式时间:北京时间2017年2月28日(周二)晚上19:30-21:00演讲人: 何增耀,《数据模型资源手册(卷3)——数据模型通用模式》译者,现为ECPT产业互联网平台总架构师,......
  • Spring Resource和策略模式应用
    Spring把所有能记录信息的载体,如各种类型的文件、二进制流等都称为资源,对Spring开发者来说,最常用的资源就是Spring配置文件(通常是一份XML格式的文件)。在Sun所提供......
  • ThinkPHP6.0开启多应用模式的方法
    ThinkPHP发展至今已经到了6..0.X版本,整个结构较thinkphp5有了很大的变化,ThinkPHP6.0基于精简核心和统一用法两大原则在5.1的基础上对底层架构做了进一步的优化改进,并更加规......
  • 04-Go设计模式-抽象工厂方法模式
    抽象工厂方法模式代码/*抽象工厂方法模式从工厂方法模式可以看出来:(1)当添加一个新产品的时候,比如葡萄,虽然不用修改代码,但是需要添加大量的类,而且还需要添加相对的工厂......
  • js异步编程的三种模式
    写在前面javascript语言的执行环境是"单线程"(singlethread),就是指一次只能完成一件任务。如果有多个任务,就必须排队,等前面一个任务完成,再执行后面一个任务,以此类推。......
  • 四句话,让我掌握了工厂模式!
    写在前面: 初为职场新手,难免会把代码写的一把梭。遇到业务的时候直接if-else干。但是本着不想被开除的原则,还是学习一下设计模式,今天来看看设计模式之工厂模式。用需求引出......
  • (转载)【RocketMQ 课程笔记】16.实现集群消费模式与广播消费模式
    集群消费模式与广播消费模式环境准备生产者CmProducer生产者是一致的,循环生成10条普通消息投给给Broker,主题为:cm-sample-data,Tag:test,Key:n@Slf4jpublicclassCmPro......