每天学习一个设计模式(十八):行为型之备忘录模式

一、基本概念

备忘录模式(Memento Pattern)提供了一种弥补真实世界缺陷的方法,让“后悔药”在程序的世界中真实可行,其定义如下:Without violating encapsulation,capture and externalize an object's internal state so that the object canbe restored to this state later.(在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。)

二、通俗解释

MEMENTO备忘录模式:同时跟几个MM聊天时,一定要记清楚刚才跟MM说了些什么话,不然MM发现了会不高兴的哦,幸亏我有个备忘录,刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存,这样可以随时察看以前的记录啦。 备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

三、备忘录模式详解

1.通用模版

通俗地说,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法,其通用类图如图所示。

我们来看看类图中的三个角色。

●Originator发起人角色

记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。

●Memento备忘录角色

负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。

●Caretaker备忘录管理员角色

对备忘录进行管理、保存和提供备忘录。

备忘录模式的通用代码也非常简单,我们先看发起人角色。

public class Originator {
    /**
     * 内部状态
     */
    private String state;

    public String getState() {
        return state;
    }

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

    /**
     * 创建一个备忘录
     *
     * @return
     */
    public Memento createMemento() {
        return new Memento(this.state);
    }

    /**
     * 恢复一个备忘录
     *
     * @param memento
     */
    public void restoreMemento(Memento memento) {
        this.setState(memento.getState());
    }
}

我相信你心里此刻有很多疑问,比如状态是多个怎么办?需要有多份备份怎么办?我们再来看备忘录角色。

public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return this.state;
    }

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

这是一个简单的JavaBean,备忘录管理者也是一个简单的JavaBean。

public class Caretaker {
    // 备忘录对象
    private Memento memento;

    public Memento getMemento() {
        return this.memento;
    }

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

这3个主要角色都很简单,我们来看场景类如何调用。

public class Client {
    public static void main(String[] args) {
        //来一个发起人
        Originator originator = new Originator();
        //来一个备忘录管理员
        Caretaker caretaker = new Caretaker();
        //管理员存储发起人的备忘录
        caretaker.setMemento(originator.createMemento());
        //发起人从管理员获取备忘录进行回滚
        originator.restoreMemento(caretaker.getMemento());
    }
}

备忘录模式就是这么简单,真正使用备忘录模式的时候可比这复杂得多。

2.备忘录模式的应用

由于备忘录模式有太多的变形和处理方式,每种方式都有它自己的优点和缺点,标准的备忘录模式很难在项目中遇到,基本上都有一些变换处理方式。因此,我们在使用备忘录模式时主要了解如何应用以及需要注意哪些事项就成了。

使用场景

需要保存和恢复数据的相关状态场景。提供一个可回滚(rollback)的操作;比如Word中的CTRL+Z组合键,IE浏览器中的后退按钮,文件管理器上的backspace键等。需要监控的副本场景中。例如要监控一个对象的属性,但是监控又不应该作为系统的主业务来调用,它只是边缘应用,即使出现监控不准、错误报警也影响不大,因此一般的做法是备份一个主线程中的对象,然后由分析程序来分析。数据库连接的事务管理就是用的备忘录模式,想想看,如果你要实现一个JDBC驱动,你怎么来实现事务?还不是用备忘录模式嘛!

注意事项

●备忘录的生命期

备忘录创建出来就要在“最近”的代码中使用,要主动管理它的生命周期,建立就要使用,不使用就要立刻删除其引用,等待垃圾回收器对它的回收处理。

●备忘录的性能

不要在频繁建立备份的场景中使用备忘录模式(比如一个for循环中),原因有二:一是控制不了备忘录建立的对象数量;二是大对象的建立是要消耗资源的,系统的性能需要考虑。因此,如果出现这样的代码,设计师就应该好好想想怎么修改架构了。

优缺点

优点:

1、简化发起人实体类(Originator)职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节;

2、提供状态回滚功能

缺点:

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


参考秦小波的《设计模式之禅(第2版)》

posted @ 2020-06-13 15:25  ${简简单单}  阅读(29)  评论(0编辑  收藏  举报