zoukankan      html  css  js  c++  java
  • 大话设计模式笔记(十五)の备忘录模式

    举个栗子

    问题描述

    打游戏存进度。

    简单实现

    GameRole

    /**
     * 游戏角色
     * Created by callmeDevil on 2019/8/11.
     */
    public class GameRole {
    
        // 生命力
        private int vit;
        // 攻击力
        private int atk;
        // 防御力
        private int def;
    
        // 状态显示
        public void stateDisplay() {
            System.out.println("角色当前状态:");
            System.out.println(String.format("体力:%s", this.vit));
            System.out.println(String.format("攻击力:%s", this.atk));
            System.out.println(String.format("防御力:%s", this.def));
            System.out.println();
        }
    
        //  获得初始状态
        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;
        }
    
        // 省略 get set
        
    }
    

    测试

    public class Test {
        public static void main(String[] args) {
            // 大战Boss前
            GameRole lufi = new GameRole();
            // 获得初始角色状态
            lufi.getInitState();
            lufi.stateDisplay();
            // 通过“游戏角色”新实例,保存进度
            GameRole backup = new GameRole();
            backup.setVit(lufi.getVit());
            backup.setAtk(lufi.getAtk());
            backup.setDef(lufi.getDef());
            // 大战Boss时,损耗严重,全部为0
            lufi.fight();
            lufi.stateDisplay();
            // GameOver不甘心,恢复进度,重新玩过
            lufi.setVit(backup.getVit());
            lufi.setAtk(backup.getAtk());
            lufi.setDef(backup.getDef());
            lufi.stateDisplay();
        }
    }
    

    测试结果

    角色当前状态:
    体力:100
    攻击力:100
    防御力:100
    
    角色当前状态:
    体力:0
    攻击力:0
    防御力:0
    
    角色当前状态:
    体力:100
    攻击力:100
    防御力:100
    

    存在问题

    在客户端调用这段,把整个游戏角色的细节暴露了,职责太大,需要知道游戏角色的生命力、攻击力、防御力这些细节,还要进行备份。如果以后需要增加“魔法力”或修改现有的某种力,那这部分代码就需要修改,同样恢复时也是一样的问题。

    备忘录模式

    定义

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

    UML图

    代码实现

    GameRole

    /**
     * 游戏角色
     * Created by callmeDevil on 2019/8/11.
     */
    public class GameRole {
    
        // 属性与简单实现GameRole相同
    
        // 保存角色状态
        public RoleStateMemento saveState() {
            return new RoleStateMemento(vit, atk, def);
        }
    
        // 恢复角色状态
        public void recoveryState(RoleStateMemento memento) {
            this.vit = memento.getVit();
            this.atk = memento.getAtk();
            this.def = memento.getDef();
        }
    
        // 其余方法与简单实现相同
        
    }
    

    RoleStateMemento

    /**
     * 角色状态存储类
     * Created by callmeDevil on 2019/8/11.
     */
    public class RoleStateMemento {
    
        // 属性与 简单实现 GameRole 相同
    
        // 将生命力、攻击力、防御力存入状态存储箱对象中
        public RoleStateMemento(int vit, int atk, int def){
            this.vit = vit;
            this.atk = atk;
            this.def = def;
        }
    
        // 省略 get set
    
    }
    
    

    RoleStateCaretaker

    /**
     * 游戏状态管理者
     * Created by callmeDevil on 2019/8/11.
     */
    public class RoleStateCaretaker {
    
        private RoleStateMemento memento;
    
        // 省略 get set
    
    }
    

    测试

    public class Test {
        public static void main(String[] args) {
            // 大战Boss前
            GameRole lufi = new GameRole();
            lufi.getInitState();
            lufi.stateDisplay();
            // 保存游戏进度
            RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
            stateAdmin.setMemento(lufi.saveState());// 将具体数据封装在了 Memento中
            // 大战Boss时,损耗严重
            lufi.fight();
            lufi.stateDisplay();
            // 恢复状态
            lufi.recoveryState(stateAdmin.getMemento());
            lufi.stateDisplay();
        }
    }
    

    测试结果

    与简单实现相同

    总结

    • 把要保存的细节给封装在了 Memento 中,哪一天要更改保存细节也不用影响客户端。
    • 备忘录模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性的一小部分时,Originator 可以根据保存的 Memento 信息还原到前一状态。
    • 如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。
    • 使用备忘录可以把复杂的对象内部信息对其他的对象屏蔽起来。
  • 相关阅读:
    A1082 Read Number in Chinese [汉字读数字]
    A1077 Kuchiguse [字符串找相同后缀]
    A1035 Password [修改字符]
    A1001 A+B Format [字符串处理]
    django文档总结之会话保持、视图、中间件(2)
    django文档总结之基本操作(1)
    VSCode常用命令快捷键
    vscode配置远程免密
    linux下deb包的管理及制作 | 一次成功
    shell脚本之sed详解(1)
  • 原文地址:https://www.cnblogs.com/call-me-devil/p/11335226.html
Copyright © 2011-2022 走看看