Java设计模式(23)-备忘录模式
中国有句古话:"千金难买后悔药"。生活中很多时候,我们做过了的事情,虽然后悔,却无济于事。但是,在软件世界,我们却可以自己制作"后悔药"。比如,以前玩"仙剑",每每遇到Boss战,那必须要存档的,就算没打过也可以恢复存档再来一次,否则,玩过的人都知道,哭去吧……这里的游戏存档,就会用到今天说的——备忘录模式。 其实还有很多这种例子,比如Word等办公软件的撤销操作,撤销后需要恢复到前一状态;又比如,虚拟机或者今天的云服务器都支持创建快照,如果系统出问题了,可以直接恢复到快照版本…… 1. 概念 备忘录,顾名思义用来做备份的,后续可能按照备份数据进行恢复。DP 对备忘录模式的定义如下: 定义 备忘录模式(Memento Pattern):在 不破坏封装性 的前提下,捕获一个对象的内部状态,将在 该对象之外 保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 这个定义比较好理解,其基本思想就是要将对象的内部状态保存下来,便于之后恢复,但是保存的逻辑不由对象本身负责,而是单独抽出取来,减轻对象的职责,同时也便于扩展。这个思想与前边的 迭代器模式] 非常类似。 需要保存内部状态的这个对象,我们称为 原发器 (Originator),抽取出来的保存原发器状态的对象我们称为 备忘录 (Memento),我们来看看它们之间的关系。 2. 结构 备忘录模式的结构如下: 可以看到,备忘录模式中有三种角色: Originator: 即原发器,持有内部状态,提供创建备忘录的方法,以保存某个时刻内部的全部或部分状态,同时还提供还原的方法,从而支持后续可以还原到保存的状态 Memento: 备忘录对象,它存储 Originator 的状态,但要求它能够防止除了 Originator 之外的对象访问备忘录 Caretaker: 管理者,它负责管理备忘录,包括存储、删除操作,但是要求它本身不能访问和修改备忘录 备忘录的宽窄接口 备忘录对象它要求能够防止除了 Originator 之外的对象访问备忘录,而管理者又不能访问和修改备忘录,因此,要求备忘录能够具有 宽窄两种接口,Originator 能够通过 宽接口 创建、访问、修改备忘录对象,而管理者只能使用 窄接口 存储、删除和允许他人查询备忘录,本身不能修改和访问备忘录。 备忘录模式具有如下的优缺点: 抽取了备忘录对象,用来保存状态,减轻了原发器的职责 备忘录和原发器都可以再次抽象出单独的接口,便于扩展 备忘录会创建多个状态的副本,可能造成很大的开销 管理者管理多个备忘录,但它并不知道备忘录的内部状态,一个小的管理者可能存储和删除很大的备忘录,带来大的开销 备忘录模式适用于以下场景: 对象需要保存自身某一时刻的状态,以便后续进行恢复 对象保存自身状态时不暴露其实现细节,需要保持其封装性不被破坏 3. 实现 备忘录模式的实现大概有三种方式,每一种都有其适用场景。 3.1. 标准实现 标准实现方式,它抽取备忘录为单独的对象,由管理者来存储。我们以仙剑游戏为例,看看示例代码实现,如下: 1、定义备忘录对象 public class Memento { private State state; public Memento(State state) { (1) this.state = state; } public State getState() { return state; } public void setState(State state) { this.state = state; } } ...