zoukankan      html  css  js  c++  java
  • 备忘录模式

    在讲述这个模式之前,我们先看一个案例:游戏回档

    游戏的某个场景,一游戏角色有生命力、攻击力、防御力等数据,在打Boss前和后会不一样,我们允许玩家如果感觉与Boss决斗的效果不理想,可以让游戏恢复到决斗前。下面是代码:

    游戏角色类,用来存储角色的生命力、攻击力、防御力的数据。

    public class GameRole {
        private int vit;//生命力
        private int atk;//攻击力
        private int def;//防御力
        
        //状态显示
        public void stateDisplay() {
            System.out.println("当前角色状态:");
            System.out.println("体力:"+this.vit);
            System.out.println("攻击力"+this.atk);
            System.out.println("防御力"+this.def);
        }
        //获取初始状态
        public void getInitState() {
            //数据通常来自本地磁盘或远程数据库
            this.vit = 100;
            this.atk = 100;
            this.def = 100;
        }
        //战斗
        public void fight() {
            //在与Boss大战后游戏数据损耗为0
            this.vit = 0;
            this.atk = 0;
            this.def = 0;
        }
        //省略getter、setter方法
        
    }
    //测试方法
    public class Test {
        public static void main(String[] args) {
            //大战Boss前
            GameRole lixiaoyao = new GameRole();
            lixiaoyao.getInitState();//Boss大战前,获得角色初始状态
            lixiaoyao.stateDisplay();
            
            //保存进度,通过游戏角色的新实例来保存进度
            GameRole backup = new GameRole();
            backup.setVit(lixiaoyao.getVit());
            backup.setAtk(lixiaoyao.getAtk());
            backup.setDef(lixiaoyao.getDef());
            
            //大战Boss时,损耗严重,所有数据全部损耗为0
            lixiaoyao.fight();
            lixiaoyao.stateDisplay();
            
            //恢复之前状态,重新来玩
            lixiaoyao.setVit(backup.getVit());
            lixiaoyao.setAtk(backup.getAtk());
            lixiaoyao.setDef(backup.getDef());
            lixiaoyao.stateDisplay();
            
        }
    }

    上面的代码实现了效果,但是不理想的是:main方法里暴露了太多“细节”,使得main方法需要知道“生命力、攻击力、防御力”这样的细节。以后需要增加“魔法值”或修改现有的“生命力”为“经验值”,这部分就要修改了。同样的道理也存在于恢复时的代码。显然,我们希望的是把这些“游戏角色”的存取状态细节封装起来,而且最好是封装在外部的类中。以体现职责分离。

    下面介绍备忘录模式:http://www.runoob.com/design-pattern/memento-pattern.html

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

    用备忘录模式优化案例

    public class GameRole {
        private int vit;//生命力
        private int atk;//攻击力
        private int def;//防御力
        
        //状态显示
        public void stateDisplay() {
            System.out.println("当前角色状态:");
            System.out.println("体力:"+this.vit);
            System.out.println("攻击力"+this.atk);
            System.out.println("防御力"+this.def);
        }
        //获取初始状态
        public void getInitState() {
            //数据通常来自本地磁盘或远程数据库
            this.vit = 100;
            this.atk = 100;
            this.def = 100;
        }
        //战斗
        public void fight() {
            //在与Boss大战后游戏数据损耗为0
            this.vit = 0;
            this.atk = 0;
            this.def = 0;
        }
        //新增“保存角色状态”方法,将游戏角色的三个状态值通过实例化“角色状态存储箱”返回
        public RoleStateMemento saveState() {
            return new RoleStateMemento(vit, atk, def);
        }
        
        //新增“恢复角色状态”方法,可将外部的“角色状态存储箱”中的状态值恢复给游戏角色
        public void recoveryState(RoleStateMemento memento) {
            this.vit = memento.getAtk();
            this.atk = memento.getAtk();
            this.def = memento.getDef();
        }
        
        //省略getter、setter方法
        
    }
    //角色状态存储箱类
    public class RoleStateMemento {
        private int vit;//生命力
        private int atk;//攻击力
        private int def;//防御力
        //将生命力、攻击力、防御力存入状态存储箱对象中
        public RoleStateMemento(int vit, int atk, int def) {
            super();
            this.vit = vit;
            this.atk = atk;
            this.def = def;
        }
        
        //省略getter、setter方法
        
    }
    //角色状态管理者类
    public class RoleStateCaretaker {
        private RoleStateMemento memento;
    
        public RoleStateMemento getMemento() {
            return memento;
        }
    
        public void setMemento(RoleStateMemento memento) {
            this.memento = memento;
        }
        
    }
    //测试方法
    public class Test {
        public static void main(String[] args) {
            //大战Boss前
            GameRole lixiaoyao = new GameRole();
            lixiaoyao.getInitState();//Boss大战前,获得角色初始状态
            lixiaoyao.stateDisplay();
            
            //保存进度,由于封装在Memento中,因此我们并不知道保存了哪些具体的数据
            RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
            stateAdmin.setMemento(lixiaoyao.saveState());
            
            //大战Boss时,损耗严重
            lixiaoyao.fight();
            lixiaoyao.stateDisplay();
            
            //恢复之前的状态
            lixiaoyao.recoveryState(stateAdmin.getMemento());
            lixiaoyao.stateDisplay();
            
        }
    }

    输出结果同上。

    肯定有人会问:对于“角色状态”的保存,直接调用RoleStateMemento进行set和get不就行了,为什么还需要一个RoleStateCaretaker类呢?

    这是为了符合迪米特法则进行的优化!

    备忘录模式也是有缺点的,角色状态需要完整存储到备忘录对象中,如果状态数据很大很多,那么在资源消耗上,备忘录对象会非常耗内存。所以也不是用的越多越好。

  • 相关阅读:
    CVS 快速入门指南
    我的博客皮肤
    OOP三个基本特征
    vi 操作
    智者能堪破这世界的定数,但没人能逃脱劫数
    技术路径的四阶段
    python每日学习2018/1/14(python之禅)
    python每日学习2018/1/11
    Python PyInstaller安装和使用教程(详解版)
    Windows环境下安装MinGW/gcc
  • 原文地址:https://www.cnblogs.com/jwen1994/p/10165657.html
Copyright © 2011-2022 走看看