备忘录模式,震撼来袭免费下载
originator.setState("stateA");
//创建备忘录对象,并将发起人对象的状态储存起来
caretaker.saveMemento(originator.createMemento());
//修改发起人的状态
originator.setState("stateB");
//恢复发起人对象的状态
originator.restoreMemento(caretaker.getMemento());
System.out.println("恢复状态:"+originator.getState());
}
}
输出结果:
多状态的备忘录模式
上面的示例代码展示的情况比较简单,Originator 中只有一个 state 成员变量需要保存,但实际中可能不止一个,会有很多个状态变量需要处理,那么在备份的时候就需要将所有的变量都存储起来,一种方法就是将变量名和对应的值都保存到一个 map 当中。当然还有比较简单的方法就是利用原型模式,我们可以将当前对象 clone 一个一模一样的对象来保存备份,通过 clone 的方式甚至都不需要备忘录管理者角色。下面是示例代码:
public class Originator implements Cloneable {
private Originator backup;
private String state;
private String state2;
private String state3;
/**
创建备份
*/
public void createMemento() {
try {
this.backup = this.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
/**
恢复备份
*/
public void restoreMemento(){
this.setState(this.backup.getState());
this.setState2(this.backup.getState2());
this.setState3(this.backup.getState3());
}
@Override
protected Originator clone() throws CloneNotSupportedException {
return (Originator) super.clone();
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getState2() {
return state2;
}
public void setState2(String state2) {
this.state2 = state2;
}
public String getState3() {
return state3;
}
public void setState3(String state3) {
this.state3 = state3;
}
}
当然,我们知道通过 clone 的方式是有缺陷的,对象的复制都是浅拷贝,这样对于那些是对象类型的成员变量还是跟原来共享的不能完全的隔离。所以最好的方式应该是使用序列化(Serializable)来进行存储。
更安全的备忘录模式
作为备份的数据,是用作将来恢复系统使用的,所以必须保证数据的完整性、纯净性,不能随意被别人修改,否则就失去了作为备份的意义。那么我们就必须想办法不让别人能够去修改它,怎么做呢,这里可以备忘录通过实现一个标识接口(空接口)的办法来对外部进行隔离。示例代码:
public class Originator {
private String state;
/**
创建备份
*/
public IMemento createMemento(){
return new Memento(state);
}
/**
恢复备份
*/
public void restoreMemento(IMemento memento){
this.state = ((Memento) memento).getState();
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + this.state);
}
private class Memento implements IMemento {
private String state;
public Memento(String state){
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
}
public interface IMemento {
}
public class Caretaker {
priv
ate IMemento memento;
/**
获取备忘录
*/
public IMemento getMemento(){
return this.memento;
}
/**
保存备忘录
*/
public void saveMemento(IMemento memento){
this.memento = memento;
}
}
可以看到我们的备忘录角色 Memento 现在是作为 Originator 的一个内部私有类,并且实现了 IMemento 接口,而 IMemento 接口是一个空接口,它什么方法也没有,Originator 在创建和恢复备份的时候都是引用的 IMemento 接口类型,而在备忘录管理者 Caretaker 对备忘录的存取也都是通过 IMemento 接口类型,这样客户端在调用过程中能接触到的只有 IMemento 接口,而它不具有任何方法,所以就避免了别人去调用它的方法进行操作。
多重备份的备忘录模式
前面介绍的都是只有一份备份数据的情况,然而在实际当中很多情况下都是要做多重数据备份的,比如我今天发现系统异常,想要将系统数据恢复到昨天甚至前天或上个星期五的状态,这个时候我们就需要有多个备份数据提供选择。可以选择恢复多重备份的点叫做检查点(check point), 检查点就是一个标记,例如它可以是一个系统的时间戳等,每个检查点会对应一个备份数据以备后期选择性恢复。示例代码:
public class Caretaker {
private HashMap<String, Memento> mementoMap = new HashMap<>();
/**
获取备忘录
*/
public Memento getMemento(String time){
return this.mementoMap.get(time);
}
/**
保存备忘录
*/
public void saveMemento(String time, Memento memento){
this.mementoMap.put(time, memento);
}
}
public class Client {
评论