TypechoJoeTheme

IT技术分享

统计

备忘录模式(Memento)——23种设计模式之行为型模式

2016-04-23
/
0 评论
/
609 阅读
/
正在检测是否收录...
04/23

在软件构建过程中,某些对象的状态在转换过 程中,可能由于某种需要,要求程序能够回溯 到对象之前处于某个点时的状态。如果使用一 些公用接口来让其他对象得到对象的状态,便 会暴露对象的细节实现。如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性?

在不破坏封装性的前提下,捕获一个对象的内部状态, 并在该对象之外保存这个状态。这样以后就可将该对 象恢复到原先保存的状态。

一个memento是一个对象, 它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器 (originator)。当需要设置原发器的检查点(checkpoint) 时, 取消操作机制会向原发器请求一个备忘录。原发器用描述当前状态的信息初始化该备忘录。只有原发器可以向备忘录中存取信息,备忘录对其他的对象 “不可见”。

一、类图表示

备忘录模式涉及Memento(备忘录),Originator(原发器),Caretaker(管理器)等角色

  • ①、Originator(原发器):创建一个备忘录,用以记录当前时刻它的内部状态,使用备忘录恢复内部状态。
  • ②、Caretaker(管理器):负责保存好备忘录,不能对备忘录的内容进行操作或检查
  • ③、Memento(备忘录):备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。防止原发器以外的其他对象访问备忘录。备忘录实际上有两 个接口,管理者(caretaker) 只能看到备忘录的窄接口—它只 能将备忘录传递给其他对象。相反, 原发器能够看到一个宽接口, 允许它访问返回到先前状态所需的所有数据。理想的 情况是只允许生成本备忘录的那个原发器访问本备忘录的内部状态。

java-memento-model-1

二、代码示例

public class Originator {

    private String state;
    /**
    * 工厂方法,返回一个新的备忘录对象
    */
    public Memento createMemento(){
        return new Memento(state);
    }
    /**
    * 将发起人恢复到备忘录对象所记载的状态
    */
    public void restoreMemento(Memento memento){
        this.state = memento.getState();
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
        System.out.println("当前状态:" + this.state);
    }

}
public class Memento {

    private String state;

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

    public String getState() {
        return state;
    }

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

}
public class Caretaker {

    private Memento memento;
    /**
    * 备忘录的取值方法
    */
    public Memento retrieveMemento(){
        return this.memento;
    }
    /**
    * 备忘录的赋值方法
    */
    public void saveMemento(Memento memento){
        this.memento = memento;
    }
}
public class Client {

    public static void main(String[] args) {

        Originator o = new Originator();
        Caretaker c = new Caretaker();
        //改变负责人对象的状态
        o.setState("On");
        //创建备忘录对象,并将发起人对象的状态储存起来
        c.saveMemento(o.createMemento());
        //修改发起人的状态
        o.setState("Off");
        //恢复发起人对象的状态
        o.restoreMemento(c.retrieveMemento());

        System.out.println(o.getState());
    }

}

三、模式分析

为了实现对备忘录对象的封装,需要对备忘录的调用进行控制,

  • ①、对于原发器而言,它可以调用备忘录的所有信息,允许原发器访问返回到先前状态所需的所有数据;
  • ②、对于管理器而言,只负责备忘录的保存并将备忘录传递给其他对象;
  • ③、对于其他对象而言,只需要从管理器处取出备忘录对象并将原发器对象的状态恢复,而无须关心备忘录的保存细节。
  • ④、理想的情况是只允许生成该备忘录的那个原发器访问 备忘录的内部状态。

四、优缺点分析

1、优点

  • ①、保持封装边界,该模式把可能很复杂的 Originator内部信息对其他对象屏蔽起来
  • ②、它简化了Originator,让客户管理它们请求的状态将会简化Originator,并且使得客户工作结束时无需通知Originator

2、缺点

  • ①、使用备忘录可能代价很高
  • ②、定义窄接口和宽接口:有些语言可能难以保证只有原发器可以访问备忘录的状态

五、模式间关系

1、与命令模式的关系

命令可使用备忘录来为可撤销的操作维护状态

2、与迭代器模式的关系

当备忘录模式支持多个checkpoints时, 在各个checkpoints之间进行遍历可用迭代模式

六、适用场景

由原发器管理, 却又必须存储在原发器之外的信息

  • ①、必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态
  • ②、如果一个用接口来让其它对象直接得到这些状 态,将会暴露对象的实现细节并破坏对象的封装性
  • ③、数据库管理系统DBMS所提供的事务管理应用了备忘录模式。当数据库某事务中一条数据操作语句执行失败时,整 个事务将进行回滚操作,系统回到事务执行之前的状态。

七、总结

在不破坏封装性的前提下,捕获一个对象的内部状态, 并在该对象之外保存这个状态。

  • ①、备忘录是被动的。只有创建备忘录的原发器会对它的状态进行赋值和检索
  • ②、一个memento是一个对象, 它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器 (originator)。
  • ③、当需要设置原发器的检查点(checkpoint)时,,取消操作机制会向原发器请求一个备忘录。原发器用描述当前状态的信息初始化该备忘录。
  • ④、只有原发器可以向备忘录中存取信息,备忘录对其他的对象“不可见”。
  • ⑤、在实现备忘录模式时,要防止原发器以外的对象访问备忘录对象。备忘录对象有两个接口:一个为原 发器使用的宽接口;一个为其他对象使用的窄接口。
  • ⑥、在实现备忘录模式时,要考虑拷贝对象状态的效率问题,如果对象开销比较大,可以采用某种增量式改变来改进备忘录模式。
朗读
赞 · 0
版权属于:

IT技术分享

本文链接:

https://idunso.com/archives/1965/(转载时请注明本文出处及文章链接)