1. 何为备忘录模式
备忘录模式(memento)是指在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。
这个模式有三个关键角色:原发器(Originator)、备忘录(Memento)和看管人(caretaker)。其思想非常简单,原发器创建一个包含其状态的备忘录,并传给看管人。看管人不知道如何与备忘录交互,但会把备忘录放在安全之处保管好。它们的静态关系如图1-1所示:
图1-1 备忘录模式结构的类图当看管人请求Originator对象保存其状态时,Originator对象将使用其内部状态创建一个新的Memento实例。然后看管人保管Memento实例,或者把它保存到文件系统,一段时间后再把它传回给Originator对象。Originator对象不知道这个Memento对象将如何被保存。看管人也不知道Memento对象里是什么。图1-2中的时序图解释了他们之间的交互过程。
图1-2 备忘录模式的时序图这个设计的关键是维持Memento对象的私有性,只让Originator对象访问保存在Memento对象的内部状态(即Originator过去的内部状态)。Memento类应该有两个接口:一个宽接口,给Originator用;一个窄接口,给其它对象用。上面图中的setState:、 state和init方法应该定义为私有,不让Originator和Memento以外的对象使用。
2. 应用场景及代码实现
一般来说满足一下两个条件时,应当考虑使用这一模式:
- 需要保存一个对象(或部分)在某一个时刻的状态,这样以后就可以恢复到先前的状态;
- 用于获取状态的接口会暴露实现的细节,需要将其隐藏起来。
备忘录模式在棋类游戏(悔棋)、普通软件(撤销操作)、数据库软件(事物管理的回滚操作)和Photoshop软件中体现较多。这里以游戏存档为例:
import Foundation
class Game {
var time: Float = 0
var pattern: String = ""
var progress: Float = 0
func saveMemento() -> Memento {
return Memento(pattern: self.pattern, progress: self.progress)
}
}
class Memento {
var pattern: String = ""
var progress: Float = 0
convenience init(pattern: String, progress: Float) {
self.init()
self.pattern = pattern
self.progress = progress
}
}
class CareTaker {
var memento: Memento?
}
let game: Game = Game()
game.time = 2500
game.pattern = "1V1"
game.progress = 0.2
print("当前游戏的模式:\(game.pattern)---游戏的进度:\(game.progress)")
let caretaker: CareTaker = CareTaker()
caretaker.memento = game.saveMemento()
game.progress = 0.5
print("当前游戏的模式:\(game.pattern)---游戏的进度:\(game.progress)")
print("备份游戏的模式:\(caretaker.memento!.pattern)---游戏的进度:\(caretaker.memento!.progress)")
运行结果:
当前游戏的模式:1V1---游戏的进度:0.2
当前游戏的模式:1V1---游戏的进度:0.5
备份游戏的模式:1V1---游戏的进度:0.2
3. 优缺点
-
优点:
- 状态恢复机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原.
- 信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作.
-
缺点:
- 资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源.
网友评论