备忘录模式

114 阅读3分钟

定义

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

优缺点

优点

  1. 封装性:通过备忘录对象存储发起人的内部状态,避免了直接暴露和修改其私有信息,提高了系统的封装性和安全性
  2. 撤销/重做功能:备忘录模式可以方便地实现复杂对象的撤销和恢复操作,例如在图形编辑器或文本编辑器中实现“撤销”和“重做”功能
  3. 状态管理:简化了对系统状态历史记录的管理,能够保存和恢复到任意的历史状态点。
  4. 事务处理:适用于需要进行事务回滚的场景,如数据库中的事务控制。

缺点

  1. 资源消耗:如果频繁的创建并存储备忘录,尤其是在系统状态数据量较大时,可能会占用较多的内存资源。特别是在需要支持大量历史状态的情况下,可能造成内存开销过大。
  2. 设计复杂度增加:为了实现备忘录模式,需要额外定义备忘录接口和具体备忘录类,以及与发起人的交互逻辑,增加了代码的复杂性。
  3. 过多备忘录管理的问题:对于长期运行的应用程序,如何管理和清理不再需要的备忘录是一个挑战,需要合理设计垃圾回收策略。
  4. 过度使用导致设计混乱:在不需要复杂状态恢复或撤销操作的情况下过度使用备忘录模式可能导致系统设计过于复杂化,违背了设计原则。应根据实际需求选择合适的模式应用。

结构图和代码示例

image.png

  • Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态。提供创建和恢复状态的方法,通常包括 createMemento() 和 setMemento(Memento m) 方法。
  • Memento(备忘录):备忘录对象负责存储发起人的内部状态信息,但对外提供的接口仅限于发起人可以访问。通常是一个私有的数据类,防止外部直接修改内部状态。
  • Caretaker(管理者):管理者负责保存和恢复发起人的备忘录,但它不能访问备忘录内部所存储的具体状态细节。可以维护一个备忘录栈或者列表,实现多个状态的回溯。
public class Originator {
    private String state;

    public String getState() {
        return state;
    }

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

    public Memento createMemento() {
        return new Memento(state);
    }

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

    public void show() {
        System.out.println("State=" + state);
    }
}

public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    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;
    }
}
public class TestApi {
    public static void main(String[] args) {
        Originator o = new Originator();
        o.setState("On");
        o.show();

        Caretaker c = new Caretaker();
        c.setMemento(o.createMemento());

        o.setState("Off");
        o.show();

        o.setMemento(c.getMemento());
        o.show();
    }
}