简易理解设计模式之:备忘录模式——Word文档的工作原理

介绍:

备忘录模式属于行为型模式。它的定义为:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。

类图:
备忘录模式UML类图.png
Originator(发起人角色):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可以使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的哪些内部状态。

Memento(备忘录角色):负责存储Originator对象的内部状态,并可防止Originator意外的其它对象访问备忘录。

Caretaker(管理者角色):负责保存好备忘录Memento,不能对备忘录的内容进行操作。

用法:
• 需要保存一个对象在某一时刻的状态
• 一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其内部状态

个人理解:
• 备忘录模式的应用场景就是存档或备份相关的业务了。如果有需要提供撤销和恢复操作的需求,可以考虑使用备忘录模式,比如:数据库备份与还原、编辑器撤销与重做、游戏存档、Git版本管理等。

• 关键字就是存档和恢复了,存取的操作可以是存到本地的磁盘或者数据库,又或者是new一个对象作为缓存保存在内存当中。一般来说,备忘录模式中的存取操作是将对象保存到内存当中去的。

例子:
我们使用Word文档编辑,首先写完一篇文章,点完保存的操作才能顺利保存文本内容,下面我们模拟一下这个逻辑:

需求:模拟Word文档的业务

1、普通方法(第一版代码)
1.1、定好架构
首先用逆向思维大概构想这个功能。从使用端的角度来说,最后的调用大概是这样子:

  Word w = new Word();
  w.edit("哈哈哈");
  w.save();
  w.edit("哈哈哈哈123");
  w.restore();

1.2、生成Word类

public class Word {
    private String text;

    /**
     * 编辑文档
     *
     * @param text
     */
    public void edit(String text) {
        this.text = text;
    }

    /**
     * 保存文档
     */
    public void save() {
        //将text属性存到本地或数据库
    }

    /**
     * 恢复文档
     */
    public void restore() {
        //从本地或数据库得到text属性
    }

    @Override
    public String toString() {
        return "文本内容为:" + text;
    }
}

好简单,为了将text保存到本地或者数据库,实现save()和restore()方法就可以了。我们的平常在开发中的做法就是生成多一个数据管理类进行数据的管理。

1.3、生成WordDB类

public class WordDB {
    private String text;
    private static WordDB mInstance;

    public static WordDB getInstance(){
        if (mInstance == null){
            mInstance = new WordDB();
        }
        return mInstance;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

这里简单用单例模拟一下,负责存取一个文本内容。那在1.2中save()方法和restore()方法的实现如下:

/**

  • 保存文档
    */
    public void save() {
    //将text属性存到本地或数据库
    WordDB.getInstance().setText(text);
    }

/**

  • 恢复文档
    */
    public void restore() {
    //从本地得到text属性或数据库
    this.text = WordDB.getInstance().getText();
    }

1.4、测试与实现

public static void main(String[] args) {
    Word w = new Word();
    w.edit("哈哈哈");
    System.out.println(w.toString());
    w.save();
    System.out.println("=====执行保存操作=====");
    w.edit("哈哈哈哈123");
    System.out.println("重新编辑," + w.toString());
    w.restore();
    System.out.println("=====执行恢复操作=====");
    System.out.println("恢复后," + w.toString());
}
文本内容为:哈哈哈
=====执行保存操作=====
重新编辑,文本内容为:哈哈哈哈123
=====执行恢复操作=====
恢复后,文本内容为:哈哈哈

执行save()方法,相当于将text内容插入进了WordDB中去,而执行resotre()就是WordDB中把数据拿回来。

1.5、分析
这里是我们很常用的做法,也就是简单的模拟一下本次存储功能。这种简单的“存档”功能并不需要运用到备忘录模式。

2、使用备忘录模式优化(第二版代码)
我们让功能复杂一点点,我们可以随便获取某一次的保存的历史记录,看看如何实现吧。

历史记录1 历史记录2 历史记录3 历史记录4 历史记录5 历史记录6 历史记录7
在第一版的例子中,我们把数据存档存到本地磁盘或者是数据库中,相当于点击了“保存”按钮。而备忘录角色的存储属于临时存储,也就是某一个过渡的状态,相当于点击了“撤销”和“重做”按钮。

2.1、创建备忘录角色WordMemento类

public class WordMemento {
    private String text;

    public WordMemento(String text) {
        this.text = text;
    }

    public String getText(){
        return text;
    }
}

使用上,备忘录角色直接将临时状态的变量保存到内存中。理解上,这种撤销和重做的功能并不需要关掉Word后再重新打开,也没必要存到本地磁盘中。

2.2、创建管理者角色WordCaretaker

public class WordCaretaker {

    private List<WordMemento> mementos = new ArrayList<>();

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

    public void setMemento(WordMemento db) {
        mementos.add(db);
    }

}

历史记录当然不止一条,每一次的输出结果都是有顺序的,所以这个用了一个List集合去操作备忘录角色。

2.3、扩充Word类为WordOriginator
在1.2的例子上,我们扩展一下功能

public class WordOriginator {
    private String text;
    /**
     * 编辑文档,每编辑完一次做一下保存
     *
     * @param text
     */
    public WordMemento edit(String text) {
        this.text = text;
        return new WordMemento(text);
    }
    /**
     * 恢复操作,获取上次的状态
     */
    public void restoreMemento(WordMemento m) {
        this.text = m.getText();
    }
    /**
     * 最终保存文档
     */
    public void save() {
        //将text属性存到本地或数据库
        WordDB.getInstance().setText(text);
    }
    /**
     * 重新打开时,恢复文档
     */
    public void restore() {
        //从本地得到text属性或数据库
        this.text = WordDB.getInstance().getText();
    }

    @Override
    public String toString() {
        return "文本内容为:" + text;
    }
}

修改了edit()方法,在每次编辑的同时,保存到备忘录(就是跟Word一样的效果)。再来一个restoreMemento()恢复方法,获取某次状态的效果。

2.4、修改客户端使用类

public class WordClient {

    private static int index = -1;
    private static WordCaretaker c = new WordCaretaker();

    public static void main(String[] args) {
        WordOriginator word = new WordOriginator();
        edit(word, "今天");
        edit(word, "今天天气");
        edit(word, "今天天气真好");
        edit(word, "今天天气真好,出去逛逛!");
        undo(word);
        undo(word);
        redo(word);
        redo(word);
    }

    /**
     * 打开文档
     */
    public static void open(WordOriginator originator) {
        originator.restore();
    }

    /**
     * 关闭文档
     */
    public static void close(WordOriginator originator) {
        originator.save();
    }

    /**
     * 编辑文档
     */
    public static void edit(WordOriginator originator, String text) {
        c.setMemento(originator.edit(text));
        index++;
        System.out.println("编辑操作," + originator.toString());
    }

    /**
     * 撤销操作
     */
    public static void undo(WordOriginator originator) {
        index--;
        originator.restoreMemento(c.getMemento(index));
        System.out.println("撤销操作," + originator.toString());
    }

    /**
     * 重做操作
     */
    public static void redo(WordOriginator originator) {
        index++;
        originator.restoreMemento(c.getMemento(index));
        System.out.println("重做操作," + originator.toString());
    }


}


    /**
     * 打开文档
     */
    public static void open(WordOriginator originator){
        originator.restore();
    }

    /**
     * 关闭文档
     */
    public static void close(WordOriginator originator){
        originator.save();
    }

    /**
     * 编辑文档
     */
    public static void edit(WordOriginator originator,String text){
        c.setMemento(originator.edit(text));
        index++;
    }

    /**
     * 撤销操作
     */
    public static void undo(WordOriginator originator){
        index--;
        originator.restoreMemento(c.getMemento(index));
    }

    /**
     * 重做操作
     */
    public static void redo(WordOriginator originator){
        index++;
        originator.restoreMemento(c.getMemento(index));
    }
}
编辑操作,文本内容为:今天
编辑操作,文本内容为:今天天气
编辑操作,文本内容为:今天天气真好
编辑操作,文本内容为:今天天气真好,出去逛逛!
撤销操作,文本内容为:今天天气真好
撤销操作,文本内容为:今天天气
重做操作,文本内容为:今天天气真好
重做操作,文本内容为:今天天气真好,出去逛逛!

总结:
此模式结构不复杂,简单来说就是备忘录角色负责缓存数据,管理者角色负责存取备忘录,发起人角色负责将数据传给备忘录和从备忘录中拿数据。很明显,资源过多需要占用大量的存储空间,资源有限的情况下这个模式要慎重使用。

感谢您的阅读~

推荐阅读

基础篇:
设计模式前篇之——UML类图必会知识点
设计模式前篇之——一起过一下面向对象的概念
创建型模式:
简易理解设计模式之:简单工厂模式——来试试接入支付功能
简易理解设计模式之:工厂方法模式——数据存储例子
简易理解设计模式之:抽象工厂模式——更换数据库例子
简易理解设计模式之:建造者模式——学习使用“链式调用”
简易理解设计模式之:原型模式——深、浅拷贝的概念
简易理解设计模式之:单例模式——单例模式的几种常用写法
结构型模式:
简易理解设计模式之:适配器模式——Android列表视图控件设计方式
简易理解设计模式之:桥接模式——穿衣服经典案例2
简易理解设计模式之:组合模式——实现View中的树状结构
简易理解设计模式之:装饰模式——穿衣服经典案例
简易理解设计模式之:外观模式——第三方SDK的帮助类
简易理解设计模式之:享元模式——五子棋游戏例子
简易理解设计模式之:代理模式——iOS视图控件设计方式
行为型模式:
简易理解设计模式之:策略模式——优化一下支付功能
简易理解设计模式之:模板方法模式——Android中的BaseActivity基类
简易理解设计模式之:观察者模式——监听与回调
简易理解设计模式之:状态模式——优化登录操作
简易理解设计模式之:备忘录模式——Word文档的工作原理
简易理解设计模式之:迭代器模式——遍历对象的好帮手
简易理解设计模式之:命令模式——实现命令的参数化配置
简易理解设计模式之:责任链模式——OA中请假流程示例
简易理解设计模式之:中介者模式——多人聊天室例子
简易理解设计模式之:解释器模式——语言和文法
简易理解设计模式之:访问者模式——员工考核例子

发布了109 篇原创文章 · 获赞 40 · 访问量 6172

猜你喜欢

转载自blog.csdn.net/qq_15719613/article/details/105158438