MEMENTO备忘录模式
1、 意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将对象恢复到原先保存的状态。
2、 适用性
在下面情况下可以使用MEMENTO模式
- 必须保存一个对象在某一时刻的(部分)状态,这样以后需要时它能恢复到先前的状态。
- 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
3、 结构
4、 参与者
Memento(备忘录)
——备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
——防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者只能看到备忘录的窄接口——它只能将备忘录传递给其他对象。相反,原发器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生成本备忘录的那个原发器访问本备忘录的内部状态。
Originator(原发器)
——原发器创建一个备忘录,用以记录当前时刻它的内部状态。
——使用备忘录恢复内部状态。
Caretaker(负责人)
——负责保持好备忘录。
——不能对备忘录的内容进行操作或检查。
5、 协作
- 管理器想原发器请求一个备忘录,保留一段时间后,将其送回给原发器。
- 备忘录是被动的。只有创建备忘录的原发器会对它的状态进行赋值和检索。
6、 效果
1) 保持封装边界。使用备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息。
2) 它简化了原发器。在其他的保持封装性的设计中,Originator负责保持客户请求过的内部版本。这就把原有存储管理的重任交给了Originator。让客户管理它们请求的状态将会简化Originator,并且使得客户工作结束时无需通知原发器。
3) 使用备忘录可能代价很高。如果原发器在生成备忘录时必须拷贝并存储大量的信息,或者客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销。
4) 定义窄接口和宽接口。
5) 维护备忘录的潜在代价。管理器负责删除它所维护的备忘录。然而,管理器不知道备忘录中有多少个状态。因此当存储备忘录时,一个本来很小的管理器,可能会产生大量的存储开销。
7、 代码示例
1) 语言支持。备忘录有两个接口,一个为原发器准备的宽接口;一个为其他对象准备的窄接口。
2) 存储增量式改变。如果备忘录的创建及其返回(给它们的原发器)的顺序是可预测的,备忘录可以仅存储原发器内部状态的增量改变。
8、 代码示例
Memento
package com.examples.pattern.memento;
/**
* 备忘录的窄接口,没有任何方法定义
*/
public interface Memento {
}
Originator
package com.examples.pattern.memento;
/**
* 原发器对象
*/
public class Originator implements Memento {
/**
* 示意,原发器的状态
*/
private String state = "";
public Originator(String state) {
this.state = state;
}
/**
* 创建保存原发器对象的状态的备忘录对象
*
* @return 创建好的备忘录对象
*/
public Memento createMemento() {
return new MementoImpl(state);
}
/**
* 重新设置原发器对象的状态,让其回到备忘录对象记录的状态
*
* @param memento
* 记录有有原发器状态的备忘录对象
*/
public void setMemento(Memento memento) {
MementoImpl mementoImpl = (MementoImpl) memento;
this.state = mementoImpl.getState();
}
public void operate_1() {
System.out.println("operate_1 :" + this.state);
}
public void operate_2() {
System.out.println("operate_2 :" + this.state);
}
private static class MementoImpl implements Memento {
private String state = "";
public MementoImpl(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
}
Caretaker
package com.examples.pattern.memento;
/**
* 负责保存的备忘录对象
*/
public class Caretaker {
/**
* 记录被保存的备忘录对象
*/
private Memento memento = null;
/**
* 保存备忘录对象
*
* @param memento
* 被保存的备忘录对象
*/
public void saveMemento(Memento memento) {
this.memento = memento;
}
/**
* 获取被保存的备忘录对象
*
* @return 被保存的备忘录对象
*/
public Memento retriveMemento() {
return this.memento;
}
}
Client
package com.examples.pattern.memento;
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
Originator originator = new Originator("STATE");
Caretaker caretaker = new Caretaker();
Memento memento = originator.createMemento();
caretaker.saveMemento(memento);
originator.operate_1();
originator.operate_2();
}
}
9、 相关模式
Command:命令可使用备忘录来为可撤销的操作维护状态。
Iterator:备忘录可用于迭代。