设计模式——备忘录模式

243 阅读3分钟

一、概述

备忘录模式在GOF的定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。备忘录每个手机中都有,可能有的叫便签或者书签,当我们需要记一些重要的事时,我们就把它写在备忘录里,当下次进来的时候就可以看到当前备忘录中的最新内容;写作时的草稿、游戏里的存档等等都是备忘录的模式。

备忘录模式的特点就是保证被保存的对象状态不能被对象从外部访问。目的是保证状态的完整性和内部实现不暴露。备忘录模式包含3个角色:

  • 备忘录角色(Memorandum):用于存储Originator的内部状态,并且可以防止Originator以外的对象访问Memorandum;
  • 发起角色(Originator):创建一个备忘录,用以记录当前时刻它的内部状态,并在需要时使用备忘录恢复内部状态。
  • 管理者角色(Caretaker):负责存储备忘录,不能对备忘录的内容进行操作和访问,只能够将备忘录传递给其他对象。

下面就以文章写作为例来具体说明。

二、使用

首先创建备忘录角色Memorandum类,它和Originator的内部属性是一样的。

/**
 * 备忘录角色
 */
public class Memorandum {

    //写作字数
    private int writeCount;
    //写作语言
    private String language;
    //写作时间
    private String time;

    public int getWriteCount() {
        return writeCount;
    }

    public void setWriteCount(int writeCount) {
        this.writeCount = writeCount;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

接下来是发起角色Originator类,在Originator中它是一个发起的角色,所以用了模拟开始写作、停止写作等操作,并打印出相关的当前状态。

/**
 * 发起角色——文章写作
 */
public class Originator {

    private static final String TAG = "XXX";

    //写作字数
    private int writeCount;
    //写作语言
    private String language;
    //写作时间
    private String time;

    public int getWriteCount() {
        return writeCount;
    }

    public void setWriteCount(int writeCount) {
        this.writeCount = writeCount;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    @Override
    public String toString() {
        return "在:" + time + ",使用:" + language + ",写了:" + writeCount + "个字";
    }

    /**
     * 开始写作
     */
    public void startWrite(){
        writeCount = 800;
        language = "中文";
        time = "7月20日";
        Log.e(TAG, "开始写作。" + toString());
    }

    /**
     * 停止写作
     */
    public void stopWrite(){
        Log.e(TAG, "停止写作");
    }

    /**
     * 保存写作状态
     */
    public Memorandum saveWrite(){
        Memorandum memorandum = new Memorandum();
        memorandum.setWriteCount(writeCount);
        memorandum.setLanguage(language);
        memorandum.setTime(time);
        return memorandum;
    }

    /**
     * 恢复写作
     */
    public void restoreWrite(Memorandum memorandum){
        this.writeCount = memorandum.getWriteCount();
        this.language = memorandum.getLanguage();
        this.time = memorandum.getTime();
        Log.e(TAG, "恢复写作。" + toString());
    }
}

再者就是管理者角色Caretaker类。这个类很简单,只是简单的持有备忘录的对象引用,不能对备忘录进行任何的修改。只是复制传递备忘录对象给其他的对象。

/**
 * 管理者角色
 */
public class Caretaker {

    private Memorandum memorandum;

    public Memorandum getMemorandum() {
        return memorandum;
    }

    public void setMemorandum(Memorandum memorandum) {
        this.memorandum = memorandum;
    }
}

最后进行测试。先创建写作发起对象,开始写作,然后创建了管理角色的对象并引用Memorandum对象,最后把Memorandum对象传给发起对象。打印输出如下图。

Originator originator = new Originator();
originator.startWrite();
Caretaker caretaker = new Caretaker();
caretaker.setMemorandum(originator.saveWrite());
originator.stopWrite();
originator.restoreWrite(caretaker.getMemorandum());

三、总结

备忘录模式不仅在思想上简单,并且在代码的使用上也很简单,通过用单独的类来保存和读取状态,这样就避免直接访问数据以及其中的内部实现。发起角色Originator状态的备份与恢复,发起人自身不需要管理与操作,而是由客户端自行按需要处理,并且发起角色的状态出现问题,可以很轻松的恢复。

github地址:github.com/leewell5717…

四、参考

详解Java设计模式之备忘录模式的使用

java设计模式-备忘录模式