• 大话设计模式读书笔记(备忘录模式)


    人物:大鸟,小菜

    事件:大鸟和小菜聊NBA火箭对爵士,最后2分落后输了的事,小菜想到如果能像游戏一样可以存档多好,打不赢再来一次,大鸟借此引出备忘录模式


     备忘录模式:

    1.小菜先直接用代码实现保存游戏进度

    2.介绍了备忘录模式

    3.结合备忘录模式实现保存游戏

    用代码实现游戏存进度

    游戏角色类:

    @Data
    @Slf4j
    public class GameRole {
        /**
         * 生命力
         */
        private int vit;
        /**
         * 攻击力
         */
        private int atk;
        /**
         * 防御力
         */
        private int def;
    
        /**
         * 状态显示
         */
        public void stateDisplay() {
            log.info("角色当前状态:");
            log.info("体力:{}", this.vit);
            log.info("攻击力:{}", this.atk);
            log.info("防御力:{}", this.def);
        }
    
        /**
         * 获得初始状态
         */
        public void getInitState() {
            this.vit = 100;
            this.atk = 100;
            this.def = 100;
        }
    
        /**
         * 战斗
         */
        public void fight() {
            this.vit = 0;
            this.atk = 0;
            this.def = 0;
        }
    }

    客户端调用:

    public class GameClient {
        public static void main(String[] args) {
            //大战boss前
            GameRole lixiaoyao = new GameRole();
            lixiaoyao.getInitState();
            lixiaoyao.stateDisplay();
    
            //保存进度
            GameRole backup = new GameRole();
            backup.setVit(lixiaoyao.getVit());
            backup.setAtk(lixiaoyao.getAtk());
            backup.setDef(lixiaoyao.getDef());
    
            //大战boss时,损耗严重
            lixiaoyao.fight();
            lixiaoyao.stateDisplay();
    
            //恢复之前状态
            lixiaoyao.setVit(backup.getVit());
            lixiaoyao.setAtk(backup.getAtk());
            lixiaoyao.setDef(backup.getDef());
    
            lixiaoyao.stateDisplay();
        }
    }

    输出结果:

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

    大鸟:代码无措未必优,在客户端的调用时,把整个游戏细节暴露在了客户端,不足取。显然我们希望把游戏的存取细节封装起来,以体现职责分离。

    备忘录模式

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

    2.结构图:

    (1)Originator:

       角色:发起人 

       功能:负责创建一个备忘录Memento,用来记录当前时刻它的内部状态,并可使用备忘录恢复内部状态,并能根据需要决定Memento存储Originator的哪些内部状态

    (2)Memento:

       角色:备忘录

       功能:负责存储Originator的内部状态,并能防止Originator以外的对象访问备忘录Memento。它提供两个接口,一个是Caretaker,只能看到备忘录的窄接口,只能将备忘录传递给其他对象,另一个是Originator能看到的宽接口,允许它访问返回到先前状态所需的所有数据。

    (3)Caretaker:

       角色:管理者

       功能:负责保存好备忘录Memento,且不能对备忘录的内容操作或检查。

    3.什么时候适用于备忘录模式?

      答:备忘录模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性一小部分时,Originator就可以根据Memento还原到前一状态,在实际场景中如命令的撤销功能。

    4.基本代码如下:

    发起人(Originator类):

    @Data
    @Slf4j
    public class Originator {
        private String state;
    
        public Memento createMemento() {
            return new Memento(state);
        }
    
        public void setMemento(Memento memento) {
            state = memento.getState();
        }
    
        public void show() {
            log.info("State= " + state);
        }
    }

    备忘录(Memento类):

    @Data
    public class Memento {
        private String state;
    
        public Memento(String state) {
            this.state = state;
        }
    }

    管理者(Caretaker类):

    @Data
    public class Caretaker {
        private Memento memento;
    }

    客户端程序:

    public class GameClient {
        public static void main(String[] args) {
            Originator o = new Originator();
            o.setState("On");
            o.show();
    
            Caretaker c = new Caretaker();
            c.setMemento(o.createMemento());
    
            o.setState("Off");
            o.show();
    
            o.setMemento(c.getMemento());
            o.show();
        }
    }

    输出结果:

    State= On
    State= Off
    State= On

    结合备忘录模式完成游戏进度保存

    1.结构图:

    2.实现代码如下:

    在之前的游戏角色类中,新增保存角色状态,和恢复角色状态的方法

    /**
     * 保存角色状态
     *
     * @return
     */
    public RoleStateMemento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }
    
    /**
     * 恢复角色状态
     *
     * @param memento
     */
    public void recoveryState(RoleStateMemento memento) {
        this.vit = memento.getVit();
        this.atk = memento.getAtk();
        this.def = memento.getDef();
    }

    角色状态存储箱类:

    @Data
    public class RoleStateMemento {
        /**
         * 生命力
         */
        private int vit;
        /**
         * 攻击力
         */
        private int atk;
        /**
         * 防御力
         */
        private int def;
    
        public RoleStateMemento(int vit, int atk, int def) {
            this.vit = vit;
            this.atk = atk;
            this.def = def;
        }
    }

    角色状态管理者类:

    @Data
    public class RoleStateCaretaker {
        private RoleStateMemento memento;
    }

    客户端代码(做到了隐藏了细节):

    public class GameClient {
        public static void main(String[] args) {
            //大战boss前
            GameRole lixiaoyao = new GameRole();
            lixiaoyao.getInitState();
            lixiaoyao.stateDisplay();
    
            //保存进度
            RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
            stateAdmin.setMemento(lixiaoyao.saveState());
    
            //大战boss时,损耗严重
            lixiaoyao.fight();
            lixiaoyao.stateDisplay();
    
            //恢复之前状态
            lixiaoyao.recoveryState(stateAdmin.getMemento());
            lixiaoyao.stateDisplay();
        }
    }

    注意:备忘录模式也是有缺点的,因为角色对象需要完整存储到备忘录对象中,如果状态数据很大,那么会非常消耗资源,备忘录对象会非常耗内存。

  • 相关阅读:
    ranorex
    vue.js
    逻辑思维
    laravel-luntan
    python学习--基础
    git
    Laravel-高级篇-Auth-数据迁移-数据填充
    Laravel-高级篇-Artisan
    Laravel-表单篇-零散信息
    Laravel-表单篇-controller
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13438899.html
Copyright © 2020-2023  润新知