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

人物:大鸟,小菜

事件:大鸟和小菜聊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();
    }
}

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

原文地址:https://www.cnblogs.com/wencheng9012/p/13438899.html