观世音甘泉活树的故事竟然是Java设计模式:备忘录模式
定义
备忘录模式是对象的行为型模式,备忘录对象是一个用来存储另外一个对象内部状态的快照的对象,备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化存储起来,从而可以使得在将来合适的时候把这个对象还原到存储起来的状态
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
主要解决问题
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态
何时使用
很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃
优缺点
优点:
- 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这个时候使用备忘录模式,可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以保持封装的边界
- 当发起人角色的状态改变时,有可能这个状态无效,这个时候就可以使用暂时存储起来的备忘录将状态复原
缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存
结构
涉及的角色:
-
备忘录(Memento)角色:
- 将发起人(Originator)对象的内部状态存储起来;备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态
- 备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取,备忘录有两个等效的接口:
- 窄接口:负责人(Caretaker)对象和其他除发起人对象之外的任何对象,看到的是备忘录的窄接口,这个接口只允许它把备忘录对象传给其他的对象
- 宽接口:发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复发起人对象的内部状态
-
发起人(Originator)角色:
- 创建一个含有当前的内部状态的备忘录对象
- 使用备忘录对象存储其内部状态
-
负责人(Caretaker)角色:
- 负责保存备忘录对象
- 不检查备忘录对象的内容
白箱实现
将发起人角色的状态存储在一个大家都看的到的地方,因此是破坏封装性的
源码如下:
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 this.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 this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
}
}
public class Caretaker {
private Memento memento;
/** 备忘录的取值方法 */
public Memento getMemento() {
return this.memento;
}
/** 备忘录的赋值方法 */
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
//改变发起人对象的状态
originator.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
caretaker.setMemento(originator.createMemento());
//修改发起人对象的状态
originator.setState("Off");
originator.restoreMemento(caretaker.getMemento());
//恢复发起人对象的状态
System.out.println("恢复状态:" + originator.getState());
}
}
黑箱实现
将Memento类设成Originator类的内部类,在外部提供一个标识接口MementoIF给Caretaker类以及其他对象
源码如下:
public class Originator {
private String state;
public Originator() {
}
/** 返回一个新的备忘录对象 */
public MementoIF createMemento() {
return new Memento(this.state);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(MementoIF memento) {
Memento memento1 = (Memento) memento;
this.state = memento1.getState();
}
/** 状态的取值方法 */
public String getState() {
return this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + this.state);
}
/** 内部成员类,备忘录 */
protected class Memento implements MementoIF {
private String saveState;
private Memento(String state) {
this.saveState = state;
}
/** 状态的取值方法 */
private String getState() {
return this.saveState;
}
/** 状态的赋值方法 */
private void setState(String state) {
this.saveState = state;
}
}
}
public interface MementoIF {
}
public class Caretaker {
private MementoIF memento;
/** 备忘录的取值方法 */
public MementoIF getMemento() {
return this.memento;
}
/** 备忘录的赋值方法 */
public void setMemento(MementoIF memento) {
this.memento = memento;
}
}
public class Client {
private static Originator o = new Originator();
private static Caretaker c = new Caretaker();
public static void main(String[] args) {
//改变发起人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
c.setMemento(o.createMemento());
//修改发起人对象的状态
o.setState("Off");
o.restoreMemento(c.getMemento());
//恢复发起人对象的状态
System.out.println("恢复状态:" + o.getState());
}
}
多重检查点
存储多个状态,或者叫做有多个检查点
public class Originator {
private Vector states;
private int index;
public Originator() {
this.states = new Vector();
this.index = 0;
}
/** 返回一个新的备忘录对象 */
public Memento createMemento() {
return new Memento(states, index);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(Memento memento) {
this.states = memento.getStates();
this.index = memento.getIndex();
}
/** 状态的赋值方法 */
public void setState(String state) {
this.states.addElement(state);
index++;
}
/** 打印出所有的状态 */
public void printStates() {
System.out.println("总的状态数量:" + index);
for (Enumeration e = states.elements(); e.hasMoreElements();) {
System.out.println(e.nextElement());
}
}
}
public class Memento {
private Vector states;
private int index;
public Memento(Vector states, int index) {
this.states = (Vector) states.clone();
this.index = index;
}
/** 状态的取值方法 */
public Vector getStates() {
return states;
}
/** 检查点指数的取值方法 */
public int getIndex() {
return index;
}
}
public class Caretaker {
private Originator originator;
private Vector vector = new Vector();
private int current;
public Caretaker(Originator originator) {
this.originator = originator;
this.current = 0;
}
/** 创建一个新的检查点 */
public int createMemento() {
Memento memento = originator.createMemento();
vector.addElement(memento);
return current++;
}
/** 将发起人恢复到某个检查点 */
public void restoreMemento(int index) {
Memento memento = (Memento) vector.elementAt(index);
originator.restoreMemento(memento);
}
/** 将某个检查点删除 */
public void removeMemento(int index) {
vector.removeElementAt(index);
}
}
public class Client {
private static Originator o = new Originator();
private static Caretaker c = new Caretaker(o);
public static void main(String[] args) {
//改变状态
o.setState("state 0");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 1");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 2");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 3");
//建立一个检查点
c.createMemento();
//打印所有的检查点
o.printStates();
//恢复到第1个检查点
System.out.println("恢复到第1个检查点");
c.restoreMemento(1);
o.printStates();
//恢复到第3个检查点
System.out.println("恢复到第2个检查点");
c.restoreMemento(2);
o.printStates();
}
}
观世音甘泉活树的故事
孙大圣保护唐僧西行,路过万寿山五庄观,与道童发生口角,一时发怒,把人参果树推倒;大圣只好请观世音菩萨救活人参果树
在这里,果树的状态保存在观世音的甘露之中,菩萨可以从甘露中把果树的状态恢复过来,果树是发起人角色,甘露是备忘录角色,菩萨是负责人角色
public class SweetSpringWater {
private String fruiterState;
public SweetSpringWater(String fruiterState) {
this.fruiterState = fruiterState;
}
/** 获取果树的状态 */
public String getFruiterState() {
return fruiterState;
}
/** 设置果树的状态 */
public void setFruiterState(String fruiterState) {
this.fruiterState = fruiterState;
}
}
public class Fruiter {
private String fruiterState;
/** 返回一个新的备忘录对象 */
public SweetSpringWater createMemento() {
return new SweetSpringWater(fruiterState);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreSweetSpringWater(SweetSpringWater springWater) {
this.fruiterState = springWater.getFruiterState();
}
/** 果树状态的取值方法 */
public String getState() {
return this.fruiterState;
}
/** 果树状态态的赋值方法 */
public void setState(String fruiterState) {
this.fruiterState = fruiterState;
System.out.println("当前果树状态:" + this.fruiterState);
}
}
public class Goddess {
private SweetSpringWater sweetSpringWater;
/** 备忘录的取值方法 */
public SweetSpringWater getSweetSpringWater() {
return this.sweetSpringWater;
}
/** 备忘录的赋值方法 */
public void setMemento(SweetSpringWater sweetSpringWater) {
this.sweetSpringWater = sweetSpringWater;
}
}
public class Client {
public static void main(String[] args) {
Fruiter f = new Fruiter();
Goddess g = new Goddess();
//改变发起人对象的状态
f.setState("果树被孙悟空推倒了");
//创建备忘录对象,并将发起人对象的状态存储起来
g.setMemento(f.createMemento());
//修改发起人对象的状态
f.setState("观世音用甘泉恢复果树状态");
//恢复发起人对象的状态
System.out.println("恢复状态:" + f.getState());
}
}