基本需求

  • 游戏的角色有攻击力和防御力,在大战Boss之前保存自身的状态(攻击力和防御力),当大战Boss之后攻击力和防御力下降,从备忘录对象恢复到大战前的状态

传统方案

  • 一个对象,就对应一个保存对象状态的对象

  • 说明

    • 一个对象,就对应一个保存对象状态的对象,这样当我们游戏的对象很多时,不利于管理,开销也很大
    • 传统的方式是简单的做备份,new出来另外一个对象出来,再把需要备份的数据放到这个新对象,但这就暴露了对象内部的细节
    • 可以使用备忘录模式进行解决

基本介绍

  • 备忘录模式(Memento)在 不破坏封装性的前提下,捕获 一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态

  • 可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某

    种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作

  • 备忘录模式属于行为型模式

  • UML类图(原理)

    • 说明

      • Originator:对象,需要保存状态的对象
      • Memento:备忘录对象,保存目标对象Originator的内部状态
      • Caretaker:守护者对象,保存多个备忘录对象,使用集合管理,提高效率
      • 如果希望保存多个Originator对象不同时间的状态,可使用Map<String,List>进行管理
    • 代码实现

      • // 备忘录对象
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public class Memento { private String state; } // 目标对象
        @Data
        public class Originator { private String state; // 创建备忘录对象,用户备份
        public Memento createMemento() {
        return new Memento(this.state);
        } // 从备忘录对象恢复对象
        public void restoreFromMemento(Memento memento) {
        this.state = memento.getState();
        }
        } // 守护者对象
        public class Caretaker { // 使用集合对备忘录对象进行管理
        private List<Memento> mementos; public Caretaker() {
        this.mementos = new ArrayList<>();
        } // 添加备忘录对象
        public void add(Memento memento) {
        mementos.add(memento);
        } // 根据索引在集合中获取备忘录对象
        public Memento getMementoByIndex(int index) {
        Memento memento = null;
        if (index >= 0 && index < mementos.size()) {
        memento = mementos.get(index);
        }
        return memento;
        }
        } // 测试
        public class Client {
        public static void main(String[] args) {
        // 创建守护者对象
        Caretaker caretaker = new Caretaker();
        // 创建目标对象 并设置状态1
        Originator originator = new Originator();
        originator.setState("状态1 -> 开心");
        // 保存状态1 -> 获取备忘录对象,并交由守护者管理
        caretaker.add(originator.createMemento());
        // 给目标状态设置状态2
        originator.setState("状态2 -> 悲伤");
        // 保存状态2 -> 获取备忘录对象,并交由守护者管理
        caretaker.add(originator.createMemento());
        // 给目标状态设置状态3
        originator.setState("状态3 -> 笑哭");
        // 保存状态3 -> 获取备忘录对象,并交由守护者管理
        caretaker.add(originator.createMemento());
        // 目标对象当前的状态
        System.out.println("目标对象当前的状态是:" + originator.getState());
        // 从守护者对象中获取备忘录对象,恢复目标对象状态至状态1
        originator.restoreFromMemento(caretaker.getMementoByIndex(0));
        System.out.println("目标对象状态恢复到状态1:" + originator.getState());
        }
        }
  • UML类图(案例)

    • 代码实现

      • // 备忘录对象
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public class Memento { // 攻击力
        private int attack; // 防御力
        private int defense; } // 游戏角色 亦目标对象
        @Data
        public class GameRole { // 攻击力
        private int attack; // 防御力
        private int defense; // 创建目标对象当前状态的备忘录对象
        public Memento createMemento() {
        return new Memento(this.attack, this.defense);
        } // 从备忘录对象中恢复目标对象
        public void restoreFromMemento(Memento memento) {
        this.attack = memento.getAttack();
        this.defense = memento.getDefense();
        } // 显示目标对象当前状态
        public void display() {
        System.out.println("目标对象当前状态,攻击力 -> " + this.attack + "、防御力 -> " + this.defense);
        }
        } // 守护者对象 对备忘录对象进行管理
        @Data
        public class Caretaker { // 只保存一次状态 根据本次需求 只需保存一次
        private Memento memento;
        // 保存一个目标对象的多次状态
        // private List<Memento> mementos;
        // 保存多个目标对象的多次状态
        // private Map<String, List<Memento>> listMap; } // 测试
        public class Client {
        public static void main(String[] args) {
        // 创建守护者对象 管理备忘录对象
        Caretaker caretaker = new Caretaker();
        // 创建目标对象 并设置初始值
        GameRole gameRole = new GameRole();
        gameRole.setAttack(100);
        gameRole.setDefense(100);
        // 获取目标对象当前状态的备忘录对象,并保存至守护者对象中
        caretaker.setMemento(gameRole.createMemento());
        // 和boss大战前 输出目标对象状态
        System.out.println("和boss大战前");
        gameRole.display();
        // 和boss大战中 输出目标对象状态
        System.out.println("和boss大战中");
        gameRole.setAttack(50);
        gameRole.setDefense(50);
        gameRole.display();
        // 和boss大战后 使用备忘录对象恢复目标对象状态至初始状态
        gameRole.restoreFromMemento(caretaker.getMemento());
        System.out.println("和boss大战后,恢复至初始状态");
        gameRole.display();
        }
        }

注意事项

  • 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便的回到某个历史状态
  • 实现了信息封装,使得用户不需要关心状态的保存细节
  • 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存
  • 应用场景:1、后悔药,2、游戏存档,3、ctrl+z,4、ie中的后退,5、数据库的事务管理
  • 为了节约内存,备忘录模式可以和原型模式配合使用

19.java设计模式之备忘录模式的更多相关文章

  1. 折腾Java设计模式之备忘录模式

    原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's int ...

  2. java设计模式之备忘录模式

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

  3. java设计模式9.备忘录模式、访问者模式、调停者模式

    备忘录模式 备忘录模式又叫快照模式,备忘录对象是一个用来存储另外一个对象内部状态快照的对象.备忘录的用意是在不破坏封装的条件下,将一个对象的状态捕捉,并外部化存储起来,从而可以在将来合适的时候把这个对 ...

  4. Java设计模式应用——备忘录模式

    备忘录模式主要用于存档.游戏中我们打boss前总会存档,如果打boss失败,则读取存档,重新挑战boss. 可以看出来,备忘录模式一般包括如下数据结构 1. 存档文件:用于恢复备份场景的必要数据: 2 ...

  5. 观世音甘泉活树的故事竟然是Java设计模式:备忘录模式

    目录 定义 意图 主要解决问题 何时使用 优缺点 结构 白箱实现 黑箱实现 多重检查点 观世音甘泉活树的故事 定义 备忘录模式是对象的行为型模式,备忘录对象是一个用来存储另外一个对象内部状态的快照的对 ...

  6. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  7. Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景

    我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...

  8. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  9. 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern)

    原文:乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) 作者:webabc ...

随机推荐

  1. bilibili插件推荐

    目前看到的好的插件就两个,现在来介绍一下. 第一个是 哔哩哔哩助手 这是它的功能,这里就以截图来给大家看 以上为这个插件的所有功能. 点击前往官网 第二个是 bilibili网页端添加APP首页推荐 ...

  2. AWT05-对话框

    1.Dialog Dialog组件是Window的子类,是容器类,是特殊组件. Dialog是可以独立存在的顶级窗口,使用上和普通窗口几乎没有区别,但应注意以下两点: 1.对话框通常依赖于其他窗口,也 ...

  3. CI/CD持续集成方案

    一,CI/CD流程和持续交付简介 CI(Continuous Integration)持续集成  CD(Continuous Deployment)持续部署  CD(Continuous delive ...

  4. druid数据源yml配置

    application.yml配置 spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:33 ...

  5. SpringBoot-2.3镜像方案为什么要做多个layer

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. 解决Linux所有命令不能使用的问题

    解决Linux所有命令不能使用的问题 出现这个问题说明你的 /etc/profile 配置出现了问题,一般是因为path配置出现了问题.排除添加内容中的错误,然后重启一个新窗口执行执行 source ...

  7. Mac电脑完美解决 BasicIPv6ValidationError 问题,通过命令行更改ip设置

    在更改mac电脑ip网络时,提示BasicIPv6ValidationError.

  8. 1-解决java Scanner出现 java.util.NoSuchElementException

    起因:在函数中新建scanner对象,然后多次调用此方法出现上述异常 原因:Scanner(system.in)在Scanner中接受的是键盘 输入,当调用close()方法时 Scanner的关闭会 ...

  9. 容器编排系统k8s之Service资源

    前文我们了解了k8s上的DemonSet.Job和CronJob控制器的相关话题,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14157306.html:今 ...

  10. ext4和xfs文件系统的扩容和收缩

    1. LVM逻辑卷管理 2. ext4文件系统 2.1 扩容CentOS6的根文件系统(ext4) 根文件系统在 /dev/VolGroup/lv_root 逻辑卷上,文件系统类型为ext4,大小为1 ...