补注:
1.为了防止Client直接实例化Memento并将其写到CareTaker中,建议将Memento类作为Originator的内部类,这样只能通过Originator访问Memento,最终实现了安全性。
2.此外,一般一个Originator对应一个Memento。如果多个Originator都对应一个Memento,因为之前将Memento类作为Originator的内部类,所以有必要提取出这个内嵌类到一个抽象类中,然后让所有的Originator泛化它——使用Template方法做啦。
3.再举一个例子。编辑Word文档的时候,会相应生成许多隐藏文件,这些其实就是这个文档不同时期的的快照,也就是Memento,只是序列化在了硬盘上保存,为了Undo机制而存在。机器重启的时候这些隐藏文件才会清除。因为它们是基于这一次打开直至关闭而创建的Memento,所以只在关闭文档前有效存在,最后到关机的时候再彻底杀掉。当然特例是非法关机(断电或冷关机),这时候再次打开系统,会发现这些隐藏文件还存在,那是因为上次非法关机,来不及清除这些“垃圾”。
另外一个例子是PhotoShop的Undo机制,我估计,因为是图像处理软件,所以Memento模式中,CareTaker中每一步存的是动作命令,比如说移动/放大/反转/加滤镜,因为动作是可逆的,所以不存快照而存命令。分析如下:
Memento模式的CareTaker中的Arraylist元素有两种存法(假设已经操作了N步,即ArrayList长度N):
一种是每次存快照,即所有对象的所有状态,这样存取的对象会比较大,但是好处是,如果想Undo至第X步,都可以一次完成:直接用索引X,找到那个时候的对象状态,用Clone方法还原到那个时间点,并且设置这个Arraylist的长度为X,不再是原来的长度;
另一种是每次存新的动作,这样存取的对象会比较小,但是如果想Undo至第X步,那么要先把ArrayList中从X开始到N的所有元素都弹出,然后每次都要重新从ArrayList的第1个元素到第X个,依次执行其相应的命令,这样操作就慢了一些——命令者模式的Undo其实就是这么实现的,用Memento作为容器存命令。