基本需求

  • 游戏的角色有攻击力和防御力,在大战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. Object not found! The requested URL was not found on this server.... 报错解决方案

    服务器(centos6.5) lnmp 报错如下 Object not found! The requested URL was not found on this server. The link ...

  2. 想用selenium ,先了解html 基础知识(5)

    二.HTML语法---了解!1.HTML超文本标记语言,是网页设计使用的语言.2.从<html>开始,到</html>结束,里面包括head和body两个部分,我们测试人员关心 ...

  3. 使用Github快速的寻找项目

    作为一个3年的码农昨天在学习项目,顺便总结一下 ,在Github找项目的几个常用方式 ,如果对您有帮助,可以点个关注,便于下次光顾! 首先我们来看一下常用命令 1.指定搜索方式 搜索文件中有spiri ...

  4. 庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署

    庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署 一.简介      我们在上一篇文章<庐山真面目之八微服务架构 NetCore 基于 Dockerfile ...

  5. 【故障公告】redis内存耗尽造成博客后台无法保存

    非常抱歉,今天上午11:00~11:30左右,由于 redis 服务器内存耗尽造成博客后台故障--保存博文时总是提示"请求太过频繁,请稍后再试",由此给您带来麻烦,请您谅解. 由于 ...

  6. Winform Dock顺序调整

    在布局的时候,当一个窗体内有多个控件使用了Dock属性来布局,Dock顺序的调整: 最近被.net winform中的控件布局搞困惑了,由于控件都是使用Dock方式的,操作起来也是比较方便,如果最大化 ...

  7. (八)、rm--删除文件或者目录

    一.命令的描述与格式 永久地删除文件或者目录,此命令具有破坏性,一旦删除,没有备份,无法恢复 格式:rm  [选项]  文件或者目录 -d或者--directory                  ...

  8. python初学者-计算小于100的最大素数

    for n in range(100,1,-1): for i in range(2,n): if n%i==0: break else: print(n,end=' ')

  9. Java Int类型与字符,汉字之间的转换

    /** * java 中的流主要是分为字节流和字符流 * 再一个角度分析的话可以分为输入流和输出流 * 输入和输出是一个相对的概念 相对的分别是jvm虚拟机的内存大小 * 从另一个角度讲Java或者用 ...

  10. redis scan 命令指南

    redis scan 命令指南 1. 模糊查询键值 redis 中模糊查询key有 keys,scan等,一下是一些具体用法. -- 命令用法:keys [pattern] keys name* -- ...