阅读 119
设计模式-备忘录模式学习之旅

设计模式-备忘录模式学习之旅

“这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战

一、什么是备忘录模式?

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

在软件系统中,备忘录模式可以为我们提供一种 “后悔药” 的机制,它通过存储系统各个历史状态的快照,使得我们可以在任一时刻将系统回滚到某一个历史状态。

二、备忘录模式的应用场景

对于我们程序员来说,可能天天都在用备忘录模式,比如我们每天使用的Git、SVN都可以提供一种代码版本撤回的功能。还有一个比较贴切的现实场景应该是游戏的存档功能,通过将游戏当前进度存储到本地文件系统或数据库中,使得下次继续游戏时,玩家可以从之前的位置继续进行。

备忘录模式适用于以下应用场景

  1. 需要保存历史快照的场景。
  2. 希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存的具体内容。

三、备忘录模式涉及的角色

首先来看下备忘录模式的通用UML类图:

image.png

从UML类图中,我们可以看到,备忘录模式主要包含三种角色:

  1. 发起人角色(Originator):负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能。
  2. 备忘录角色(Memento):用于存储Originator的内部状态,且可以防止Originator以外的对象进行访问。
  3. 备忘录管理员角色(Caretaker):负责存储,提供管理备忘录(Memento),无法对备忘录内容进行操作和访问。

四、利用压栈管理落地备忘录模式

我们肯定都用过网页中的富文本编辑器,编辑器中的通常会附带草稿箱、撤销等这样的操作。下面我们用一段代码来实现一个这样的功能。假设,我们发布一篇文章,文章编辑的过程需要花很长时间,中间也会不停地撤销、修改。甚至可能要花好几天才能写出一篇精品文章,因此可能会将已经编辑好的内容实时保存到草稿箱。

首先创建发起人角色编辑器Editor类:

@Data
@AllArgsConstructor
public class Editor {

    private String title;
    private String content;
    private String images;

    public ArticleMemento saveToMemento() {
        ArticleMemento articleMemento = new ArticleMemento(this.title, this.content, this.images);
        return articleMemento;
    }

    public void undoFromMemento(ArticleMemento articleMemento) {
        this.title = articleMemento.getTitle();
        this.content = articleMemento.getContent();
        this.images = articleMemento.getImages();
    }
}
复制代码

然后创建备忘录角色ArticleMemento类:

@Data
@AllArgsConstructor
public class ArticleMemento {

    private String title;
    private String content;
    private String images;
}
复制代码

最后创建备忘录管理角色草稿箱DraftsBox类:

public class DraftsBox {

    private final Stack<ArticleMemento> stack = new Stack<>();

    public ArticleMemento getMemento() {
        ArticleMemento articleMemento = stack.pop();
        return articleMemento;
    }

    public void addMemento(ArticleMemento articleMemento) {
        stack.push(articleMemento);
    }
}
复制代码

编写客户端测试代码:

public class Test {

    public static void main(String[] args) {
        DraftsBox draftsBox = new DraftsBox();

        Editor editor = new Editor("设计模式学习之旅", "好好学习天天向上", "666888.png");

        ArticleMemento articleMemento = editor.saveToMemento();
        draftsBox.addMemento(articleMemento);

        System.out.println("标题:" + editor.getTitle() + "\n" + "内容:" + editor.getContent() + "\n" + "插图:" + editor.getImages());
        System.out.println("完成的信息:" + editor);

        System.out.println("====首次修改文章====");
        editor.setTitle("备忘录模式");
        editor.setContent("Mark在学习此模式中。。。");
        System.out.println("====首次修改文章完成====");

        System.out.println("完成的信息:" + editor);

        articleMemento = editor.saveToMemento();
        draftsBox.addMemento(articleMemento);
        System.out.println("====保存到草稿箱====");

        System.out.println("====第二次修改文章====");
        editor.setTitle("单例模式");
        editor.setContent("Zoe在学习此模式中。。。");
        System.out.println("完成的信息:" + editor);
        System.out.println("====第二次修改文章完成====");

        System.out.println("====第一次撤销====");
        articleMemento = draftsBox.getMemento();
        editor.undoFromMemento(articleMemento);
        System.out.println("完成的信息:" + editor);
        System.out.println("====第一次撤销完成====");

        System.out.println("====第二次撤销====");
        articleMemento = draftsBox.getMemento();
        editor.undoFromMemento(articleMemento);
        System.out.println("完成的信息:" + editor);
        System.out.println("====第二次撤销完成====");
    }
}
复制代码

运行结果如下:

image.png

五、备忘录模式的优缺点

优点:

  1. 简化发起人实体类(Originator)职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节。
  2. 提供状态回滚功能。

缺点:

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

六、友情链接

设计模式-工厂模式学习之旅

设计模式-单例模式学习之旅

设计模式-原型模式学习之旅

设计模式-建造者模式学习之旅

设计模式-代理模式学习之旅

设计模式-门面模式学习之旅

设计模式-装饰器模式学习之旅

设计模式-享元模式学习之旅

设计模式-组合模式学习之旅

设计模式-适配器模式学习之旅

设计模式-桥接模式学习之旅

设计模式-委派模式学习之旅

设计模式-模板方法模式学习之旅

设计模式-策略模式学习之旅

设计模式-责任链模式学习之旅

设计模式-迭代器模式学习之旅

设计模式-命令模式学习之旅

设计模式-状态模式学习之旅

欢迎大家关注微信公众号(MarkZoe)互相学习、互相交流。

文章分类
后端
文章标签