【设计模式】备忘录模式

622 阅读4分钟

本文主要介绍备忘录模式概念和用法。

模式背景

备忘录模式是为了解决系统中状态回退,撤销问题的。比如系统功能中的回到上一步,下棋悔棋等。我们可能因为当前的状态存在了问题,需要回滚到上一个状态去。

定义&概念

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。他是一种对象行为型模式,其别名为Token。

原理

备忘录模式也是一个相对简单的设计模式,他的主要思想就是在外部再创建一个对象专门来保存一个对象的上一个状态,这个类我们就叫做备忘录类。原始对象需要自己提供对象状态的创建和恢复,但是他内部不引用这个对象(如果在内部自己引用,那么该对象职责会偏重),所以我们需要外部一个专门管理负责人的负责人类。

并且为了状态的安全考虑,我们需要对状态类对象的访问做控制:

  1. 状态类只能原始类对象来创建,以及set等方法,其他的类不允许调用。
    • java使用package访问级别来控制,状态类和原始类在同一个包中。
  2. 负责人类只负责保存备忘录对象

组成要素

  • 原发器:需要被保存状态的类
  • 备忘录:用来存储原发器的内部状态,根据原发器来决定保存哪些内部状态。注意备忘录只能被原发器来使用,不能给其他的对象修改其内部状态。
  • 负责人:管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或者检查。只负责存储备忘录对象,不可以修改它,也不需要知道备忘录内部细节。

备忘录模式中,如果负责人只管理一个对象,那么就只能撤销一步,如果管理多个状态(List),就可以撤回多次。

UML

实现

单次和多次撤销的实现。

单次撤销

原发器

public class Originator {
    private String state;

    /**
     * 创建一个备忘录对象
     */
    public Memento createMemento() {
        return new Memento(this);
    }

    /**
     * 根据备忘录对象恢复到之前的状态。
     */
    public void restoreMemento(Memento m) {
        state = m.getState();
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

备忘录

class Memento {

    private String state;

    Memento(Originator originator) {
        state = originator.getState();
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

负责人

public class Caretaker {

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

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

使用

// 创建负责人
Caretaker caretaker = new Caretaker();
Originator o = new Originator();
o.setState("1");
// 创建一个备忘录对象,保存状态,并初始化负责人的备忘录对象
caretaker.setMemento(o.createMemento());
o.setState("2");
System.out.println(o.getState());
// 恢复
o.restoreMemento(caretaker.getMemento());
System.out.println(o.getState());

多次撤销

就是在负责人类中定义一个集合来存储多个备忘录。

public class MementosTaker {
    private List<Memento> mementos = new ArrayList<>();

    public Memento getMemento(int index) {
        return mementos.get(index);
    }

    public void setMementos(Memento memento) {
        this.mementos.add(memento);
    }
}

优缺点

优点

  • 提供了一种状态恢复机制,使用户可以方便的恢复到一个特定的历史状态。
  • 实现了信息的封装,使得用户不需要关心状态的保存细节。

缺点

  • 如果类的成员变量过多,会占用比较大的内存资源,而且每一次保存都会消耗一定的内存。

使用场景

  • 一个对象需要保存该对对象在某一时刻的全部状态或者部分状态的。
  • 想要实现撤销回滚等操作的。
  • 不想让外界破坏一个对象的历史状态,并不希望将其实现细节暴露给外界的。

总结

原始类就不用多说了,主要记住该模式还有其他的2个类:专门存储状态的状态类,专门负责管理状态的负责人类。

  • 原始类,状态类放在一个包下,状态类设置访问级别为默认的package级别。
  • 原始类中包含状态对象的创建和恢复方法,创建完成了,和需要恢复的时候,都需要负责人对象来存储或者返回之前的状态对象。

相关代码:github.com/zhaohaoren/…

如有代码和文章问题,还请指正!感谢!