解释:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
结构图:
Originator(发起人),可根据需要决定Memento存储Originator的哪些内部状态。
Memento(备忘录),有两个接口,Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许将它访问返回到先前状态所需的所有数据。
Caretaker(管理者),不能对备忘录的内容进行操作、检查。
客户端:
优点:
保存的细节封装在了Memento中,修改、添加、删除不会影响客户端代码。
缺点:
状态需要完整存储到Memento中,如果状态数据很大、很多,则Memento对象会非常耗内存。不是用的越多越好。
使用环境、场合:
功能复杂,但需要维护、记录属性历史的类,或需要保存一部分属性历史的类。
Originator可以根据保存的Memento信息还原到前一状态。
使用命令模式的系统中,需要实现命令的撤销功能,可以使用备忘录模式来存储可撤销操作的状态。
对象的内部信息必须保存在对象以外的地方,但必须由对象自己读取。使用备忘录模式可以把复杂的对象内部信息对其他的对象屏蔽起来,从而可以恰当第保持封装的边界。
当状态改变时,有可能这个状态会撤销,导致无效,这时可以使用Memento将状态复原。
使用建议:
保存全部信息时,用Originator实例来做状态备份可以考虑,但是用clone的方式来实现状态备份可能是更好的办法。缺点是:对上层应用开放了Originator的全部(public)接口,不合适。
不需要备份全部状态信息时,只是部分,应该有一个独立的Memento类,只拥有需要保存的信息的属性。
应用:
1.游戏状态的各种参数存储,以便日后读取。(保存在磁盘上)
2.常规应用:悔棋、文档撤销操作、网页后退,频繁、简单的恢复。(保存在内存中)
示例:
客户端代码:
对比:
客户端暴露了实现细节,不可取。
扩展:
代码无错未必优。
不能将功能细节暴露给客户端。否则,客户端责任太大。增加、修改时困难。