备忘录模式

备忘录模式

一、备忘录模式

备忘录模式(Memento Pattern)是一种对象行为型模式,又叫快照模式,别名为Token。

定义在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。
使用频率:2星
模式结构
备忘录模式的主要角色如下:
1、发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
2、备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
3、管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
备忘录模式结构图
备忘录模式
优点
1、提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
2、实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
3、简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
缺点
资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
应用场景
1、需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
2、需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。

二、备忘录模式实例之游戏恢复点设置

1.实例说明

某游戏为了给玩家提供更好的用户体验,在游戏过程中设置一个恢复点,记录当前游戏场景,如果在后续游戏中玩家角色“不幸牺牲”,可以返回到先前场景。使用备忘录模式设计该功能。

2.实例类图

备忘录模式

3.实例代码

本例中,GameScene充当原发器角色,它是待保存历史状态的类;SceneMemento充当备忘录角色,它存储了GameScene的历史状态;Caretaker充当负责人角色,它用于管理备忘录。

//游戏场景类:原发器
class GameScene{
    private String scene;
    private int lifeValue;

    public void restore(SceneMemento m){
        this.scene=m.getScene();
        this.lifeValue=m.getLifeValue();
    }
    public SceneMemento save(){
        return new SceneMemento(this.scene,this.lifeValue);
    }
    public void display(){
        System.out.println("当前游戏场景为:"+this.scene+",");
        System.out.println("您还有"+this.lifeValue+"条命");
    }

    // Getter & Setter
    public String getScene() {
        return scene;
    }

    public void setScene(String scene) {
        this.scene = scene;
    }

    public int getLifeValue() {
        return lifeValue;
    }

    public void setLifeValue(int lifeValue) {
        this.lifeValue = lifeValue;
    }
}

//场景备忘录:备忘录
class SceneMemento{
    private String scene;
    private int lifeValue;

    public SceneMemento(String scene, int lifeValue) {
        this.scene = scene;
        this.lifeValue = lifeValue;
    }

    // Getter & Setter
    public String getScene() {
        return scene;
    }

    public void setScene(String scene) {
        this.scene = scene;
    }

    public int getLifeValue() {
        return lifeValue;
    }

    public void setLifeValue(int lifeValue) {
        this.lifeValue = lifeValue;
    }
}

//负责人
class Caretaker{
    private SceneMemento memento;

    // Getter & Setter
    public SceneMemento getMemento() {
        return memento;
    }

    public void setMemento(SceneMemento memento) {
        this.memento = memento;
    }
}

客户端测试:

public class Client {
    public static void main(String[] args) {
        GameScene scene = new GameScene();
        Caretaker ct = new Caretaker();
        scene.setScene("无名湖");
        scene.setLifeValue(3);
        System.out.println("原始状态");
        scene.display();
        ct.setMemento(scene.save());//原始状态存档
        System.out.println("------------------");

        scene.setScene("魔鬼洞");
        scene.setLifeValue(0);
        System.out.println("牺牲状态");
        scene.display();
        System.out.println("------------------");

        scene.restore(ct.getMemento());//加载原始状态存档
        System.out.println("恢复到原始状态");
        scene.display();
        System.out.println("------------------");
    }
}

运行结果:

原始状态
当前游戏场景为:无名湖,
您还有3条命
------------------
牺牲状态
当前游戏场景为:魔鬼洞,
您还有0条命
------------------
恢复到原始状态
当前游戏场景为:无名湖,
您还有3条命
------------------

原发器GameScene调用save方法后将产生一个备忘录对象,该备忘录对象将保存在Caretaker中,原发器需要恢复状态时再将其从Caretaker中取出,可以通过调用restore方法来获取存储在备忘录中的状态信息。真实开发中,除了原发器可以创建备忘录并赋值外,其他对象不应该直接调用备忘录中的方法,也不能创建备忘录。如果备忘录被原发器以外的第三者改动,则原发器恢复到历史状态不是真实的历史状态,而是修改过的,这违背了备忘录模式的设计初衷,因此需要对备忘录进行封装。

参考文献

【1】备忘录模式(详解版)
【2】设计模式实训教程(第2版) 刘伟 编著 清华大学出版社

上一篇:HMS Core助力游戏运营开发,为游戏出海开启无限可能


下一篇:HMS Core助力游戏运营开发,为游戏出海开启无限可能