备忘录设计模式

2021-01-29 设计模式架构设计

在不破坏封闭的前提下,捕获一个对象的内部状态,保存对象的某个状态,以便在适当的时候恢复对象,又叫做快照模式,备忘录模式实现的方式需要保证被保存的对象状态不能被对象从外部访问。

# 应用场景

  • 玩游戏的时候肯定有存档功能,下一次登录游戏时可以从上次退出的地方继续游戏
  • 棋盘类游戏的悔棋、数据库事务回滚
  • 需要记录一个对象的内部状态时,为了允许用户取消不确定或者错误的操作,能够恢复到原先的状态
  • 提供一个可回滚的操作,如ctrl+z、浏览器回退按钮

# 角色

  • Originator: 发起者,记录当前的内部状态,并负责创建和恢复备忘录数据,允许访问返回到先前状态所需的所有数据,可以根据需要决定Memento存储自己的哪些内部状态
  • Memento: 备忘录,负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态
  • Caretaker: 管理者,对备忘录进行管理、保存和提供备忘录,只能将备忘录传递给其他角色
  • Originator 和 Memento属性类似

# 编码实战

小张开发了一个游戏存档功能 拳皇97,无限生命,每次快要死的的时候就恢复成刚开始的状态。

创建一个角色类

@Data
public class RoleOriginator {

    /** 生命:100 */
    private int live = 100;

    /** 攻击力,会上涨 */
    private int attack = 50;

    /** 展示当前状态 */
    public void display() {
        System.out.println("开始========");
        System.out.println("生命力:" + live);
        System.out.println("攻击力:" + attack);
        System.out.println("结束========");
    }

    /** 格斗 */
    public void fight() {
        // 攻击力会上涨
        this.attack = attack + 2;
        // 打架,生命下降
        this.live = live - 10;
    }

    /** 保存快照,存储状态 */
    public RoleStateMemento saveState(){
        return new RoleStateMemento(live,attack);
    }

    /** 恢复 */
    public void recoveryState(RoleStateMemento roleStateMemento){
        this.attack = roleStateMemento.getAttack();
        this.live = roleStateMemento.getLive();
    }
}

创建一个快照类

@Data
public class RoleStateMemento {

    /**
     * 生命:100
     */
    private int live;

    /**
     * 攻击力,会上涨
     */
    private int attack;

    public RoleStateMemento(int live, int attack) {
        this.live = live;
        this.attack = attack;
    }
}

创建一个管理快照类

public class RoleStateCaretaker {

    private RoleStateMemento memento;

    public RoleStateMemento getMemento() {
        return memento;
    }

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

使用

public static void main(String[] args) {
    RoleOriginator role = new RoleOriginator();
    // 展示
    role.display();
    // 打架
    role.fight();
    role.display();

    // 保存快照
    RoleStateCaretaker caretaker = new RoleStateCaretaker();
    caretaker.setMemento(role.saveState());

    role.fight();
    role.display();
    role.fight();
    role.display();

    System.out.println("===回滚===");
    role.recoveryState(caretaker.getMemento());
    role.display();
}

最终结果

开始========
生命力:100
攻击力:50
结束========
开始========
生命力:90
攻击力:52
结束========
开始========
生命力:80
攻击力:54
结束========
开始========
生命力:70
攻击力:56
结束========
===回滚===
开始========
生命力:90
攻击力:52
结束========

# 小结

优点

  • 给用户提供了一种可以恢复状态的机制
  • 实现了信息的封装,使得用户不需要关心状态的保存细节

缺点:消耗更多的资源,而且每一次保存都会消耗一定的内存

上次更新: 1 年前