基本需求

  • 游戏的角色有攻击力和防御力,在大战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. 开始学习Django,配置静态登录页面

    开始学习Django,配置静态登录页面 准备阶段 众所周知,Django是一个重量级的设备齐全的web开发框架.在学习Django前我们需要具备如下的知识点: python基础编程 并发 网络编程 H ...

  2. K8s 终将废弃 docker,TKE 早已支持 containerd

    近日 K8s 官方称最早将在 1.23版本弃用 docker 作为容器运行时,并在博客中强调可以使用如 containerd 等 CRI 运行时来代替 docker.本文会做详细解读,并介绍 dock ...

  3. Spring MVC或Spring Boot配置默认访问页面不生效?

    相信在开发项目过程中,设置默认访问页面应该都用过.但是有时候设置了却不起作用.你知道是什么原因吗?今天就来说说我遇到的问题. 首先说说配置默认访问页面有哪几种方式. 1.tomcat配置默认访问页面 ...

  4. DRF类视图让你的代码DRY起来

    刚开始写views.py模块的代码,一般都是用def定义的函数视图,不过DRF更推荐使用class定义的类视图,这能让我们的代码更符合DRY(Don't Repeat Yourself)设计原则: 使 ...

  5. BUUCTF 刮开有奖 WriteUp

    题目链接 https://buuoj.cn/challenges#%E5%88%AE%E5%BC%80%E6%9C%89%E5%A5%96 题解 用IDA打开,按F5反编译,双击进入DialogFun ...

  6. os模块和os.path模块常用方法

    今天和大家分享python内置模块中的os模块和os.path模块. 1.什么是模块呢? 在计算机开发过程中,代码越写越多,也就越来越难以维护,所以为了可维护的代码,我们会把函数进行分组,放在不同的文 ...

  7. CentOS7 实战源码部署nginx网站服务器

    简介:实战演练nginx网站服务器的搭建 nginx 简介: Nginx是一款高性能的 HTTP 和反向代理服务器   Nginx的优点: 1.高并发量:根据官方给出的数据,能够支持高达 50,000 ...

  8. Oracle中除数为0的两种解决办法(decode与nullif)

    Oracle中Decode函数,语句DECODE(tag,''ZCGS'',0,1)=decode(''@corp-No@'',''6010'',1,0) decode(字段或字段的运算,值1,值2, ...

  9. postgresql 函数集合

    1.空间对象字段不建议手动创建,建议使用语句生成空间对象字段,table_name:表名,column_name:生成的列名,3857:坐标系 SELECT AddGeometryColumn ('p ...

  10. 如何解决Renesas USB3.0RootHub警告

    打开WINDOWS系统的[计算机管理]-[服务和应用程序]-[服务]-点击[Portable Device Enumerator Service]服务,设置为启动类型:自动(延迟启动).并点击&quo ...