《设计模式》备忘录模式

@TOC

定义

  • 备忘录模式又称为快照模式或者令牌模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
  • 属性行为型模式。

备忘录模式的角色组成

  • Originator(发起人):负责创建一个 Memento(备忘录),用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态。
  • Memento(备忘录):负责存储 Originator(发起人) 对象的内部状态,并可防止发起人以外的其他对象访问备忘录。
  • Caretaker(管理者) :负责存储、提供并管理备忘录,无法对备忘录的内容进行操作和访问。只负责存储对象,而不能修改对象,也无须知道对象的实现细节

访问者模式的 UML 类图

🎈情景案例:平时在写博客文章时,可能写到一半因为其他事中止了,这时通常将写好的内容保存到草稿(这时就是创建了一个备忘录),等有空时(或者是几天后几周后都可能)再从草稿箱中找回当时的草稿(恢复当时状态)继续撰写文章,这就是一个典型的备忘录模式的应用。

发起者 Originator 类

java 复制代码
public class Originator {
    private String state;

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

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

    public String getState() {
        return state;
    }

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

备忘录 Memento 类

java 复制代码
class Memento {
    private String state;

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

    public String getState() {
        return state;
    }

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

备忘录管理者 Caretaker 类

java 复制代码
public class Caretaker {
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

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

客户端 Client 类

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建发起者
        Originator originator = new Originator();
        originator.setState("文章进度50%");
        // 创建备忘录管理者
        Caretaker caretaker = new Caretaker();
        // 备忘录管理者暂存发起者目前的状态
        caretaker.setMemento(originator.createMemento());
        originator.setState("午休醒来朦胧状态接着午休前又写了10%,清醒之后发现写的不对,赶紧撤销修改~");
        // 撤销修改,恢复备忘录中保存的状态
        originator.setMemento(caretaker.getMemento());
    }
}

✨在设计备忘录类时需要考虑其封装性,除了 Originator 类,不允许其他类来调用备忘录类Memento 的构造函数与相关方法。如果不考虑封装性,允许其他类调用 setState() 等方法,将导致在备忘录中保存的历史状态发生改变,通过撤销操作所恢复的状态就不再是真实的历史状态,备忘录模式也就失去了本身的意义。

备忘录模式的优点

  • 实现了对信息的封装:将复杂的对象内部信息对其他的对象屏蔽,从而保持封装的边界。
  • 提供了对状态回滚的支持:使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。

备忘录模式的缺点

  • 资源消耗大:如果需要保存的状态过多,则每一次保存都会消耗很多内存。

备忘录模式的适用场景

  • 保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时就能够恢复到先前的状态,实现撤销操作。
  • 防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。

🎈备忘录模式在JDK源码 com.sun.corba.se.impl.encoding 中的应用

com.sun.corba.se.impl.encoding.CDRInputStream_1_0CORBA(Common Object Request Broker Architecture) 标准中定义的一种编解码器,它用于将Java对象序列化为二进制格式,以便在网络上进行传输。

CDRInputStream_1_0 中定义了一个名为 StreamMemento 的内部类,用于保存和恢复当前输入流的状态StreamMemento 类包含了输入流当前位置、缓冲区状态等信息,以便在需要的时候恢复输入流的状态。

CDRInputStream_1_0 源码

java 复制代码
public class CDRInputStream_1_0 extends CDRInputStreamBase
    implements RestorableInputStream {
	
	// 此处省略若干行代码

    // Mark and reset -------------------------------------------------
    protected MarkAndResetHandler markAndResetHandler = null;

    protected class StreamMemento
    {
        // These are the fields that may change after marking
        // the stream position, so we need to save them.
        private int blockLength_;
        private int end_flag_;
        private int chunkedValueNestingLevel_;
        private int valueIndirection_;
        private int stringIndirection_;
        private boolean isChunked_;
        private javax.rmi.CORBA.ValueHandler valueHandler_;
        private ByteBufferWithInfo bbwi_;
        private boolean specialNoOptionalDataState_;

        public StreamMemento()
        {
            blockLength_ = blockLength;
            end_flag_ = end_flag;
            chunkedValueNestingLevel_ = chunkedValueNestingLevel;
            valueIndirection_ = valueIndirection;
            stringIndirection_ = stringIndirection;
            isChunked_ = isChunked;
            valueHandler_ = valueHandler;
            specialNoOptionalDataState_ = specialNoOptionalDataState;
            bbwi_ = new ByteBufferWithInfo(bbwi);
        }
    }

    public java.lang.Object createStreamMemento() {
        return new StreamMemento();
    }

    public void restoreInternalState(java.lang.Object streamMemento) {

        StreamMemento mem = (StreamMemento)streamMemento;

        blockLength = mem.blockLength_;
        end_flag = mem.end_flag_;
        chunkedValueNestingLevel = mem.chunkedValueNestingLevel_;
        valueIndirection = mem.valueIndirection_;
        stringIndirection = mem.stringIndirection_;
        isChunked = mem.isChunked_;
        valueHandler = mem.valueHandler_;
        specialNoOptionalDataState = mem.specialNoOptionalDataState_;
        bbwi = mem.bbwi_;
    }

    public int getPosition() {
        return get_offset();
    }

    public void mark(int readlimit) {
        markAndResetHandler.mark(this);
    }

    public void reset() {
        markAndResetHandler.reset();
    }
    // ---------------------------------- end Mark and Reset
}

CDRInputStream_1_0 中,备忘录模式的应用,可以让输入流在需要恢复状态时,能够快速且准确地恢复到之前保存的状态,提高编解码的效率和可靠性。

相关推荐
customer0815 分钟前
【开源免费】基于SpringBoot+Vue.JS医疗报销系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
B站计算机毕业设计超人19 分钟前
计算机毕业设计SpringBoot+Vue.jst房屋租赁系统(源码+LW文档+PPT+讲解)
vue.js·spring boot·后端·eclipse·intellij-idea·mybatis·课程设计
m0_748248651 小时前
SpringBoot整合easy-es
spring boot·后端·elasticsearch
一个热爱生活的普通人2 小时前
golang的切片(Slice)底层实现解析
后端·go
红目香薰2 小时前
Trae——慧码速造——完整项目开发体验
后端
Vcats3 小时前
深入浅出:基于SpringBoot和JWT的后端鉴权系统设计与实现
java·spring boot·后端
~kiss~3 小时前
Rust~二刷异步逻辑
开发语言·后端·rust
SomeB1oody3 小时前
【Rust中级教程】2.7. API设计原则之灵活性(flexible) Pt.3:借用 vs. 拥有、`Cow`类型、可失败和阻塞的析构函数及解决办法
开发语言·后端·性能优化·rust
larance3 小时前
Flask 发送邮件
后端·python·flask
Aska_Lv3 小时前
从零到一写组件库-日志组件库
后端