设计模式-备忘录模式
备忘录(Memonto)模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。 (学习)
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。
备忘录模式的结构
备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。
备忘录角色
备忘录角色有如查责任:
- 将发起人(Originator)对象的内战状态存储起来。备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内存状态。
- 备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取。
备忘录有两个等效的接口:
- 窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄接口(narrow interface),这个窄接口只允许它把备忘录对象传给其它的对象。
- 宽接口:与负责人对象看到的窄接口相反的是,发起人对象可以看到一个宽接口(wide interface),这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态。
发起人角色
发起人角色有如下责任:
- 创建一个含有当前的内部状态的备忘录对象。
- 使用备忘录对象存储其内部状态。
负责人角色
负责人角色有如下责任:
- 负责保存备忘录对象。
- 不检查备忘对象的内容。
“白箱”备忘录模式的实现
备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。因此这个实现又叫做“白箱实现”。
“白箱”实现将发起人角色的状态存储在一个大家都看得到的地方上,因此是破坏封装性的。但是通过程序员自律,同样可以在一定程度上实现模式的大部分用意。因此白箱实现仍然是有意义的。
下面给出一个示意性的“白箱实现”。
源代码
package Memento.WhiteBox /** * 发起人角色类,发起人角色利用一个新创建的备忘录对象将自已的内部状态存储起来 * */ class Originator { var state = "" set(value) { field = value //println("当前状态:$field") } /** * 工厂方法,返回一个新的备忘录对象 * */ fun createMemento(): Memento { return Memento(state) } /** * 将发起人恢复到备忘录对象所记载的状态 * */ fun restoreMemento(memento: Memento) { this.state = memento.state } }
package Memento.WhiteBox /** * 备忘录角色类,备忘录对象将发起人对象传入的状态存储起来 * */ class Memento constructor(state: String) { var state = "" init { this.state = state } }
package Memento.WhiteBox /** * 负责人角色类,负责人角色负责保存备忘录对象,但是从不修改(甚至不查看)备忘录对象的内容 * */ class Caretaker { private var memento: Memento? = null /** * 备忘录的取值方法 * */ fun rerieveMemento(): Memento { if (memento == null) { memento = Memento("") } return memento!! } /** * 备忘录的赋值方法 * */ fun saveMemento(memento: Memento) { this.memento = memento } }
测试
val originator = Originator() val caretaker = Caretaker() //改变负责人对象的状态 originator.state = "on" //创建备忘录对象,并将发起人对象的状态储存起来 caretaker.saveMemento(originator.createMemento()) //修改发起人的状态 originator.state = "off" //恢复发起人对象的状态 originator.restoreMemento(caretaker.rerieveMemento()) println(originator.state)
在上面的这个示意性的例子里,首先将发起人对象的状态设置成"on",并创建一个备忘录对象将这个状态存储起来;然后将发起人对象的状态修改成"off";最后又将发起人对象恢复到备忘录对象所存储起来的状态,即"on"状态。