基本需求

  • 游戏的角色有攻击力和防御力,在大战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. Docker修改默认的网段

    一,问题 docker安装后默认的网段是172.17网段的,和真实环境网段冲突导致本机电脑无法连接docker机器. 二,解决办法 修改docker默认网段 1,先把docker停止 systemct ...

  2. 使用 vue 仿写的一个购物商城

    在学习了 vue 之后,决定做一个小练习,仿写了一个有关购物商城的小项目.下面就对项目做一个简单的介绍. 项目源码: github 项目的目录结构 -assets 与项目有关的静态资源,包括 css, ...

  3. Linux 搭建ELK日志收集系统

    在搭建ELK之前,首先要安装Redis和JDK,安装Redis请参考上一篇文章. 首先安装JDK及配置环境变量 1.解压安装包到/usr/local/java目录下[root@VM_0_9_cento ...

  4. MySQL 5.6.38安装

    #1.安装说明 本套安装方式适用于:CentOS6.X 或CentOS7.X系列的OS安装,此方法适用于MySQL5.6.xx版本的安装,如果是5.7版本的话不适合该配置. #2.准备安装环境 # N ...

  5. Autofac官方文档翻译--一、注册组件--2传递注册参数

    官方文档:http://docs.autofac.org/en/latest/register/parameters.html 二.Autofac 传递注册参数 当你注册组件时能够提供一组参数,可以在 ...

  6. NPOI导入excel

    1.引用NPOI: using NPOI.HSSF.UserModel;using NPOI.HSSF.Util;using NPOI.SS.UserModel; 2.导出excel 1 privat ...

  7. Redis基础篇(三)持久化:AOF日志

    Redis是内存数据库,但是一旦服务器宕机,内存中的数据将会全部丢失. 最简单的恢复方式是从后端数据库恢复,但这种方式有两个问题: 频繁访问数据库,会给数据库带来巨大的压力: 从数据库中读取相比从Re ...

  8. 创建txt文件,并且写入内容

    使用fopen的w方式就可以创建一个新的txt文件,如果文件名存在该文件内容会消失. 1. fopen的函数原型:FILE * fopen(const char * path,const char * ...

  9. springboot项目中使用jsp

    在pom文件中 1.方法一 <!-- 引入tomcate内嵌的jsp解析包--> <dependency> <groupId>org.apache.tomcat.e ...

  10. JavaSwing 船只停靠管理可视化(五)

    JavaSwing 船只停靠管理可视化(一) JavaSwing 船只停靠管理可视化(二) JavaSwing 船只停靠管理可视化(三) JavaSwing 船只停靠管理可视化(四) JavaSwin ...