19.备忘录模式

[TOC]
备忘录用来记录对象的状态(创建快照),便于撤销(回滚)。

要想恢复对象状态,需要一个可以自由访问对象内部结构的权限,但是如果不注意,可能会将依赖于对象内部结构的代码分散在程序的各处,导致程序变得难以维护,这种情况叫做破坏了封装性。

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

通用类图

image

示例代码

  • Originator
public class Originator {  
    private String state = "";  
      
    public String getState() {  
        return state;  
    }  
    public void setState(String state) {  
        this.state = state;  
    }  
    public Memento createMemento(){  
        return new Memento(this.state);  
    }  
    public void restoreMemento(Memento memento){  
        this.setState(memento.getState());  
    }  
} 
  • Caretaker
public class Caretaker {  
    private Memento memento;  
    public Memento getMemento(){  
        return memento;  
    }  
    public void setMemento(Memento memento){  
        this.memento = memento;  
    }  
}  
  • Memento
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;
    }
}

  • Client
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        originator.setState("状态1");
        System.out.println("初始状态:" + originator.getState());
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(originator.createMemento());
        originator.setState("状态2");
        System.out.println("改变后状态:" + originator.getState());
        originator.restoreMemento(caretaker.getMemento());
        System.out.println("恢复后状态:" + originator.getState());

         

    }
}
  • go
初始状态:状态1
改变后状态:状态2
恢复后状态:状态1

角色说明

  • Originator

需要保存备忘录的对象,它能够创建memento对象,且能从memento对象中恢复保存的状态,但它并不会保存备忘录对象,而是将备忘录对象寄存在CareTaker中。这样不会使Originator对象本身变得庞大,且分离开来使得Originator更加专注于自身业务,无需去管理存储的备忘信息。

  • Memento

备忘信息的载体,提供了备忘信息的副本以及操作信息的接口。在备忘录对象中,存在“宽接口”和“窄接口”的概念。

宽接口和窄接口是对于备忘录的开放程度而言的,当备忘录对象能被完全访问时,也就是方法是可以被其他接口的,就称之为宽接口,不过宽接口由于公开内部信息(保存的其他对象的备忘信息),它需要谨慎地被其他接口访问,所以宽接口一般需要限制为包访问权限,只能本包的接口可以访问其内部存储的信息。从直觉上这似乎是违反它的“宽”的概念的,但是正是由于开放性(宽开放接口),才需要控制访问(窄访问);

而窄接口则是备忘录信息不能被完全访问,所以它是窄开放的,也由于它的窄开放性,所以可以宽访问,不会影响内部数据的安全性。

示例中由于只有一个内部状态,且是public的,可以看成窄接口,业务开放了访问部分信息。

  • Caretaker
    这里的Caretaker只是提供了memento对象的暂存容器,其实它的角色可以和client合并在一起,Caretaker作为Client来保存中间状态的黑盒,提供给Originator回滚的存档,实际上这个黑盒可以放进Originator内部,但是不利于解耦,如果后期需要控制这些存档的存取方式等,放在Originator内部就需要修改Originator的代码。

Caretaker实际上是作为Client的一部分的,既然它能够访问memento对象,那么就需要将memento的接口设置成窄接口来保护内部的数据。

你可能感兴趣的:(19.备忘录模式)