基本需求

  • 游戏的角色有攻击力和防御力,在大战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. 二、TestNG的Hello World

    创建第一个TestNG的例子 1.创建一个TestNG的类 选择项目路径"右键"--NEW--Other 选择TestNG cLass(如果没有这个选项是testng没有配置成功) ...

  2. ASP .Net Core 中间件的使用(一):搭建静态文件服务器/访问指定文件

    前言 随着Asp .Net Core的升级迭代,很多开发者都逐渐倾向于.net core开发. .net core是一个跨平台的应用程序,可以在windows.Linux.macOS系统上进行开发和部 ...

  3. C++线程详细说明

    一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX ...

  4. C++ string常见函数总结

    基础概念 对照功能列表:不能直接回答的再去看相应解析说明. begin 得到指向字符串开头的 Iterator end 得到指向字符串结尾的 Iterator rbegin 得到指向反向字符串开头的 ...

  5. Ch2信息的表示和处理——caspp深入理解计算机系统

    目录 第2章 信息的表示和处理 2.1 信息存储 2.1.1 十六进制 一.表示法 二.加减 三.进制转换 2.1.2 字 2.1.3 数据大小 2.1.4 字节顺序与表示 一.字节的排列规则 二.打 ...

  6. Sqlmap 学习笔记1:sqlmap参数

    SQLMP参数分析 1 目录 1.Target Options 2.Requests Options 3.Injection Options 4.Detection Options 5.Techniq ...

  7. SpringCloud 源码系列(5)—— 负载均衡 Ribbon(下)

    SpringCloud 源码系列(4)-- 负载均衡 Ribbon(上) SpringCloud 源码系列(5)-- 负载均衡 Ribbon(下) 五.Ribbon 核心接口 前面已经了解到 Ribb ...

  8. Linux 路由 策略路由

    Linux 路由 策略路由 目录 Linux 路由 策略路由 一.路由表 编辑路由表配置文件:/etc/iproute2/rt_tables添加删除修改路由表 二.IP策略 查看IP策略 添加IP策略 ...

  9. reactor模式:主从式reactor

    前面两篇文章提到 reactor模式:单线程的reactor模式 reactor模式:多线程的reactor模式 NIO的server模式只有5个阶段,但是,NIO的selectionkey里确实有个 ...

  10. 「译」 .NET 5 新增的Http, Sockets, DNS 和 TLS 遥测

    .NET 一直在稳定的增加和改善对应用程序进行跨平台的诊断分析,在.NET Core 3.0, 我们看到了 EventCounters 的介绍,用于观察和分析指标测量. 我最近在几个 .NET Cor ...