意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。 这样以后就可将该对象恢复到原先保存的状态。
例子
|
上面建立了原发器的状态字段,以及提供对当前状态的保存以及恢复功能,使用了另一个类来存储当前状态。但是他并不会保存这些状态,只是用这些记录来恢复。
针对每一次记录都使用下面的对象来单独保存。public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
然后使用一个备忘录管理类来管理这些备忘录public class CareTaker {
private List<Memento> datas = new ArrayList<Memento>();
public void save(Memento m) {
datas.add(m)
}
public Memento get(int index) {
return datas.get(index);
}
}
接下来使用即可public class Main {
public static void main(String[] args) {
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("状态1");
careTaker.save(originator.saveCurrentStateToMemento());
originator.setState("状态2");
careTaker.save(originator.saveCurrentStateToMemento());
originator.setState("状态3");
careTaker.save(originator.saveCurrentStateToMemento());
originator.restore(careTaker.get(0));
originator.restore(careTaker.get(1));
}
}
适用性
- 必须保存一个对象在某一个时刻的 (部分)状态, 这样以后需要时它才能恢复到先前的状态。
- 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
结构
协作
- 管理器向原发器请求一个备忘录 , 保留一段时间后 ,将其送回给原发器 , 如下面的交互图所示。有时管理者不会将备忘录返回给原发器 , 因为原发器可能根本不需要退到先前的状态。
- 备忘录是被动的。只有创建备忘录的原发器会对它的状态进行赋值和检索。
效果
备忘录模式有以下一些效果 :
- 保持封装边界
使用备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发 器之外的信息。该模式把可能很复杂的 Originator 内部信息对其他对象屏蔽起来 , 从而保持了封装边界。 - 它简化了原发器
在其他的保持封装性的设计中 , Originator负责保持客户请求过的内部 状态版本。这就把所有存储管理的重任交给了 Originator 。 让客户管理它们请求的状态将会简化 Originator, 并且使得客户工作结束时无需通知原发器 。 - 使用备忘录可能代价很高
如果原发器在生成备忘录时必须拷贝并存储大量的信息 , 或者客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销。除非封装和恢复 Originator 状态的开销不大 ,否则该模式可能并不合适。 - 定义窄接口和宽接口
在一些语言中可能难以保证只有原发器可访问备忘录的状态。 - 维护备忘录的潜在代价
管理器负责删除它所维护的备忘录。然而 , 管理器不知道备忘录中有多少个状态。因此当存储备忘录时,一个本来很小的管理器,可能会产生大量的存储开销。