设计模式之备忘录模式 - 简书

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

解决方案

我们刚才遇到的所有问题都是封装 “破损” 造成的。 一些对象试图超出其职责范围的工作。 由于在执行某些行为时需要获取数据, 所以它们侵入了其他对象的私有空间, 而不是让这些对象来完成实际的工作。

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

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

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

在文字编辑器的示例中, 我们可以创建一个独立的历史 (History) 类作为负责人。 编辑器每次执行操作前, 存储在负责人中的备忘录栈都会生长。 你甚至可以在应用的 UI 中渲染该栈, 为用户显示之前的操作历史。

当用户触发撤销操作时, 历史类将从栈中取回最近的备忘录, 并将其传递给编辑器以请求进行回滚。 由于编辑器拥有对备忘录的完全访问权限, 因此它可以使用从备忘录中获取的数值来替换自身的状态。

备忘录模式结构

基于嵌套类的实现,该模式的经典实现方式依赖于许多流行编程语言 (例如 C++、 C# 和 Java) 所支持的嵌套类。

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

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

负责人 (Caretaker) 仅知道 “何时” 和 “为何” 捕捉原发器的状态, 以及何时恢复状态。

负责人通过保存备忘录栈来记录原发器的历史状态。 当原发器需要回溯历史状态时, 负责人将从栈中获取最顶部的备忘录, 并将其传递给原发器的恢复 (restoration) 方法。

在该实现方法中, 备忘录类将被嵌套在原发器中。 这样原发器就可访问备忘录的成员变量和方法, 即使这些方法被声明为私有。 另一方面, 负责人对于备忘录的成员变量和方法的访问权限非常有限: 它们只能在栈中保存备忘录, 而不能修改其状态。

JAVA 示例代码

import java.util.*;

public class MementoPattern {

    public static void main(String\[\] args) {

        Caretaker caretaker = new Caretaker();

        Originator originator = new Originator();

        originator.setState("1024");

        Memento backup1 = originator.createMemento();

        caretaker.addMemento(backup1);

        originator.setState("2048");

        Memento backup2 = originator.createMemento();

        caretaker.addMemento(backup2);

        originator.setState("4096");

        Memento backup3 = originator.createMemento();

        caretaker.addMemento(backup3);

        System.out.println(originator.getState());

        caretaker.showMemento();

        Memento memento1 = caretaker.getMemento(2);

        originator.setMemento(memento1);

        System.out.println("根据第2次备份还原之后的状态为:" + originator.getState());

    }

}

class Originator { // 原发器

    private String state;

    public void setState(String state) {

        this.state = state;

    }

    public String getState() {

        return state;

    }

    public Memento createMemento() {

        return new Memento(state);

    }

    public void setMemento(Memento memento) {

        state = memento.getState();

    }

}

class Memento { // 备忘录

    private String state;

    public Memento(String state) {

        this.state = state;

    }

    public String getState() {

        return state;

    }

}

class Caretaker { // 管理者

    private List<Memento> mementoList = new ArrayList<>();

    public void addMemento(Memento memento) {

        mementoList.add(memento);

    }

    public Memento getMemento(int index) {

        // 判断参数是否合法

        if (index >= 1 && index <= mementoList.size()) {

            return mementoList.get(index - 1);

        }

        return null;

    }

    public void showMemento() {

        int cnt = 1;

        // for (遍历对象类型 对象名 : 遍历对象)

        for (Memento memento : mementoList) {

            System.out.println("第" + cnt + "次备份,状态为:" + memento.getState());

            cnt ++ ;

        }

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

flysh05

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

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

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

打赏作者

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

抵扣说明:

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

余额充值