备忘录模式——保存和恢复内部状态

  备忘录,顾名思义就是把当时的内容保存下来,以便日后使用。在软件设计模式中,备忘录模式就是指在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将这个对象恢复到保存的时候的状态。因为平时编程中会使用数据库作为保存数据的载体,所以备忘录模式并不会有太多的使用,大多数在文本处理和日志打印等场景中才会有所使用到。

备忘录模式讲解

备忘录模式结构图

  • Memento:备忘录,主要用来存储原发器对象的内部状态。具体存储什么数据,是由原发器来决定的。备忘录可以是一个接口,也可以是一个存储对象的bean,作为接口的时候,原发器会继承这个接口,然后跳出一部分自己的数据创建一个备忘录来保存。作为对象bean的时候,通常是原发器持有这个对象,保存的时候会将这个对象的原型对象进行保存。
  • Originator:原发器。使用备忘录来保存某个时刻的状态。
  • Caretaker:备忘录的管理者,也就是保存备忘录的负责人。主要用于保存备忘录对象。

备忘录模式示例

  我们模拟一个文本编辑器来举例一下备忘录的使用,因为文本就一个内容字段,我们直接创建一个备忘录的类TextMemento,让原发器持有这个对象,同时原发器还会实现保存当前内容和恢复内容的方法。具体代码如下:

1. 创建备忘录类TextMemento

因为内部只有一个String类型的方法,我们直接用jdk的clone方法就可以实现深度clone,获得其原型对象,具体内容请参考《原型模式——java实现原型模式的几种写法》:

/**
 * 模拟文本编辑的类,在这里只有一个方法,我们用java自带的clone方法来获得原型对象
 */
public class TextMemento implements Cloneable {

    public TextMemento(String content) {
        this.content = content;
    }

    /**
     * 内容
     */
    private String content;

    public void editContent(String content) {
        this.content = content;
    }

    public void displayContent() {
        System.out.println("当前的文本为:" + content);
    }

    @Override
    protected TextMemento clone() throws CloneNotSupportedException {
        return (TextMemento) super.clone();
    }
}

2. 实现备忘录的管理者TextCaretaker,用一个栈来保存备忘录对象

/**
 * 备忘录的管理者,我们用一个stack来管理存档的数据
 */
public class TextCaretaker {

    private static final Stack<TextMemento> textMementoStack = new Stack<>();

    public static void saveMemento(TextMemento textMemento) {
        try {
            TextMemento memento = textMemento.clone();
            textMementoStack.push(memento);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static TextMemento getMemento() {
        if (textMementoStack.empty()) {
            System.out.println("没有可以恢复的数据");
            return null;
        }
        return textMementoStack.pop();
    }
}

3. 实现原发器TextOriginator

/**
 * 文本的原发器,负责管理文本的保存和恢复
 */
public class TextOriginator {

    private TextMemento currentMemento;

    public TextOriginator(TextMemento textMemento) {
        this.currentMemento = textMemento;
    }

    public void display() {
        this.currentMemento.displayContent();
    }

    public TextMemento getCurrentMemento(){
        return currentMemento;
    }

    /**
     * 备份数据
     */
    public void backupMemento() {
        TextCaretaker.saveMemento(this.currentMemento);
    }

    /**
     * 恢复数据
     */
    public void recoverMemento() {
        TextMemento memento = TextCaretaker.getMemento();
        if (memento != null) {
            this.currentMemento = memento;
        }
    }
}

4. 编写测试方法,测试备忘录的保存和恢复功能

public class Client {

    @Test
    public void testMemento(){
        TextOriginator originator = new TextOriginator(new TextMemento("这是原始的数据"));
        System.out.println("----------------原始数据并存档----------------------");
        originator.display();
        originator.backupMemento();
        System.out.println("----------------第一次修改并存档----------------------");
        originator.getCurrentMemento().editContent("第一次修改数据");
        originator.display();
        originator.backupMemento();
        System.out.println("----------------第二次修改不存档----------------------");
        originator.getCurrentMemento().editContent("第二次修改数据");
        originator.display();
        System.out.println("----------------第一次恢复后的数据----------------------");
        originator.recoverMemento();
        originator.display();
        System.out.println("----------------第二次恢复后的数据----------------------");
        originator.recoverMemento();
        originator.display();
    }
}

测试结果如下:

----------------原始数据并存档----------------------
当前的文本为:这是原始的数据
----------------第一次修改并存档----------------------
当前的文本为:第一次修改数据
----------------第二次修改不存档----------------------
当前的文本为:第二次修改数据
----------------第一次恢复后的数据----------------------
当前的文本为:第一次修改数据
----------------第二次恢复后的数据----------------------
当前的文本为:这是原始的数据

  从上面的示例中,我们可以看到,备忘录的目标是保存对象的状态,保存是手段,恢复才是目标。在具体的实现中,一定要注意保存的是备忘录对象的原型对象,除非这种保存是持久化到持久化设备中,因为java对象是引用的方式,如果内部不是获取的原型对象,在原来对象的修改中同样会修改保存的对象,恢复的时候是达不到效果的。

4. 示例结构图如下

文本备忘录示例结构图


后记
  个人总结,欢迎转载、评论、批评指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值