Memento Mode 备忘录模式
使用绘画板之类的软件时,其中有“撤销”的操作,即是返回编辑内容的上一步,多次点击可以撤销到前几步,这里涉及到“历史记录”的概念,前几次操作是存放在历史记录中,撤销的时候即是从历史记录中取出最近的一次操作,作为当前操作,这就是备忘录模式的具体应用。所以接下来,让我们来理解备忘录模式的实现吧!
It allow to save or recover the object state before without expose the object’s implemented detail. The originator can create the snapshot of itself and can restore the snapshot when it need. The memento is a value object of the originator’s snapshot state, it’s built by the initializer and pass the information by only one time. The caretaker can only use the originator’s makeMemento()
and restore()
.
它允许在不暴露对象实现细节的情况下,保存和恢复对象之前的状态。原发器可以创建它自己的快照并且在需要的时候恢复快照到自身。备忘录是一个用于存放原发器快照状态的值对象,它只通过构造函数传递状态信息。负责人只可以使用原发器的 “创建快照” 和 “恢复状态” 的方法。
// Originator
protocol Animal {
func getMemento() -> Memento
}
// Memento
protocol Memento {
func restore()
}
// Concrete originator
class Dog: Animal {
private var age: Int
private var weight: Float
private var legCount: Int
init(age: Int, weight: Float, legCount: Int) {
self.age = age
self.weight = weight
self.legCount = legCount
}
func getMemento() -> Memento {
return DogData(dog: self, age: age, weight: weight, legCount: legCount)
}
func setAge(age: Int) {
self.age = age
}
func setWeight(weight: Float) {
self.weight = weight
}
func setLegCount(legCount: Int) {
self.legCount = legCount
}
func info() -> String {
return "age: \(age) weight: \(weight) legCount: \(legCount)"
}
}
// Concrete memento
class DogData: Memento {
private var age: Int
private var weight: Float
private var legCount: Int
private var dog: Dog?
init(dog: Dog, age: Int, weight: Float, legCount: Int) {
self.dog = dog
self.age = age
self.weight = weight
self.legCount = legCount
}
// restore data from memento to originator
func restore() {
dog?.setAge(age: age)
dog?.setWeight(weight: weight)
dog?.setLegCount(legCount: legCount)
}
}
// CareTaker
class Recored {
var dog: Dog
var history: [Memento] = []
init(dog: Dog) {
self.dog = dog
}
func save() {
var backup = dog.getMemento()
history.append(backup)
if (history.count > 10) {
history.remove(at: 0)
}
}
// use stack structure to store
func undo() {
if history.count <= 0 {
return
}
var data = history[history.count - 1]
data.restore()
history.remove(at: history.count - 1)
}
}
let dog = Dog(age: 2, weight: 15, legCount: 4)
let record = Recored(dog: dog)
record.save()
print(dog.info())
dog.setAge(age: 4)
dog.setWeight(weight: 20)
print(dog.info())
record.undo()
print(dog.info())
备忘录模式,有原发器(带有数据的类本身)、负责记录者(持有原发器的引用和 “历史记录数组” 的引用)。
上方代码中,Dog 是原发器,DogData 是备忘对象,Record 是备忘录负责者。加入记录时,dog 借助自身的 save 方法生成一个备忘对象(把原发器引用给备忘对象,有利于备忘对象回忆)dogData,将备忘对象存入备忘录 record;恢复记录时,从备忘录中取出最近的一个备忘对象,调用备忘对象的 restore 方法,把备忘对象自身所带的数据恢复到自身持有的原发器引用所指的对象。
备忘对象存有原发器的副本和引用,用来存入备忘录或者从备忘录拿出后恢复到原发器。