【设计模式】行为模式——备忘录模式

行为模式——备忘录模式

一、定义

备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。

二、问题

设计一个象棋悔棋游戏,可以悔棋有限步。

三、解决方案

  • 备忘录

备忘录模式将创建状态快照的工作委派给实际状态的拥有者原发器 (Originator) 对象。 这样其他对象就不再需要从 “外部” 复制编辑器状态了, 编辑器类拥有其状态的完全访问权, 因此可以自行生成快照。

备忘录模式将对象状态的副本存储在一个名为备忘录 (Memento) 的特殊对象中。 除了创建备忘录的对象外, 任何对象都不能访问备忘录的内容。 其他对象必须使用受限接口与备忘录进行交互, 它们可以获取快照的元数据 (创建时间和操作名称等), 但不能获取快照中原始对象的状态。

这种限制策略允许你将备忘录保存在通常被称为负责人 (Caretakers) 的对象中。 由于负责人仅通过受限接口与备忘录互动, 故其无法修改存储在备忘录内部的状态。 同时, 原发器拥有对备忘录所有成员的访问权限, 从而能随时恢复其以前的状态。

四、代码实现

原发器 (Originator) 类可以生成自身状态的快照, 也可以在需要时通过快照恢复自身状态。

package com.atmae.momento;

import com.sun.istack.internal.NotNull;

/**
 * @Author: Mae
 * @Date: 2022/5/12
 * @Time: 19:10
 * @Description:
 */
public class Originator {
    private Integer x;
    private Integer y;

    /**
     * 起死回生大法
     *
     * @param m 备忘录
     */
    public void restoreMemento(@NotNull Memento m) {
        this.x = m.getX();
        this.y = m.getY();
    }

    /**
     * 起死回生 保存当前坐标
     * @return 备忘录
     */
    public Memento saveMemento(){
        return new Memento(this.x,this.y);
    }
    public Integer getX() {
        return x;
    }

    public void setPosition(Integer x, Integer y) {
        this.x = x;
        this.y = y;
    }

    public Integer getY() {
        return y;
    }


    public void show() {
        System.out.println("当前位置--->x:" + this.x + ",y:" + this.y);
    }
}

备忘录 (Memento) 是原发器状态快照的值对象 (value object)。 通常做法是将备忘录设为不可变的, 并通过构造函数一次性传递数据。

package com.atmae.momento;

import com.sun.istack.internal.NotNull;

/**
 * @Author: Mae
 * @Date: 2022/5/12
 * @Time: 19:10
 * @Description:
 */
public class Memento {
    private final Integer x;
    private final Integer y;

    public Memento(Integer x,Integer y) {
        this.x = o.getX();
        this.y = o.getY();
    }

    public Integer getX() {
        return x;
    }

    public Integer getY() {
        return y;
    }

}

负责人 (Caretaker) 仅知道 “何时” 和 “为何” 捕捉原发器的状态, 以及何时恢复状态。
负责人通过保存备忘录栈来记录原发器的历史状态。 当原发器需要回溯历史状态时, 负责人将从栈中获取最顶部的备忘录, 并将其传递给原发器的恢复 方法。

package com.atmae.momento;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Mae
 * @Date: 2022/5/12
 * @Time: 19:10
 * @Description:
 */
public class Caretaker {
    private final List<Memento> mementoes = new ArrayList<>();

    public Memento getMemento() {
        if (mementoes.size() == 0) {
            try {
                throw new Exception("你当前没有保存备忘录");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Memento memento = mementoes.get(mementoes.size() - 1);
        mementoes.remove(memento);
        return memento;
    }

    public void setMemento(Memento memento) {
        int maxNum = 5;
        if (mementoes.size() >= maxNum) {
            try {
                throw new Exception("你连续悔棋次数不能超过5次");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        mementoes.add(memento);
    }
}
package com.atmae.momento;

/**
 * @Author: Mae
 * @Date: 2022/5/12
 * @Time: 19:23
 * @Description:
 */
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        originator.setPosition(1, 1);
        originator.show();
        caretaker.setMemento(originator.saveMemento());
        originator.setPosition(2, 3);
        originator.show();

        originator.restoreMemento(caretaker.getMemento());
        originator.show();

        originator.setPosition(6, 6);
        caretaker.setMemento(originator.saveMemento());

        originator.setPosition(8, 8);
        caretaker.setMemento(originator.saveMemento());

        originator.restoreMemento(caretaker.getMemento());
        originator.show();

        originator.restoreMemento(caretaker.getMemento());
        originator.show();

    }
}

五、UML图

在这里插入图片描述

六、备忘录模式适用场景

  • 当你需要创建对象状态快照来恢复其之前的状态时, 可以使用备忘录模式。

  • 当直接访问对象的成员变量、 获取器或设置器将导致封装被突破时, 可以使用该模式。

七、总结

优点

  • 可以在不破坏对象封装情况的前提下创建对象状态快照。
  • 可以通过让负责人维护原发器状态历史记录来简化原发器代码。

缺点

  • 如果客户端过于频繁地创建备忘录, 程序将消耗大量内存。

八、与其他模式的关系

  • 有时候原型模式可以作为备忘录的一个简化版本, 其条件是你需要在历史记录中存储的对象的状态比较简单, 不需要链接其他外部资源, 或者链接可以方便地重建
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mae_strive

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值