19.备忘录模式
2018-08-14 本文已影响0人
0x70e8
[TOC]
备忘录用来记录对象的状态(创建快照),便于撤销(回滚)。
要想恢复对象状态,需要一个可以自由访问对象内部结构的权限,但是如果不注意,可能会将依赖于对象内部结构的代码分散在程序的各处,导致程序变得难以维护,这种情况叫做破坏了封装性。
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态。
通用类图
示例代码
- 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的接口设置成窄接口来保护内部的数据。