Design Pattern — Memento

在不破壞封裝性的前提下,補獲一個物件的內部狀態,並在該物件外保存這個狀態,這樣就可以將物件恢復到之前的狀態,簡單說就是備份的機制。

Evan Chen
4 min readMay 24, 2018

Memento
儲存執行個體的內部狀態

Originator
依造內部狀態建立Memento物件、利用Memento物件回復自已的狀態。

Caretaker
負責Memento物件的安全、不能修改Memento的狀態

我們以遊戲為例子,遊戲者有等級、金錢欄位,透過備忘錄模式來儲存遊戲者的等級、金錢。

建立Originator:GamePlayer,欄位有等級level、錢money, createMemento為儲存功能、setMemento為還原功能

// Originator
class GamePlayer {
//角色的等級
var level: Int = 0
//身上的錢
var money: Int = 0

//產生備忘錄(存檔)
fun createMemento():Memento{
return Memento(level, money)
}

//還原備忘錄(回復)
fun setMemento(memento: Memento){
level = memento.level
money = memento.money
}
}

Memento:用來儲存Originator的結構(遊戲存檔的結構)
Caretaker:存檔、取檔都要透過Caretaker。

//Memento 遊戲存檔的結構。
data class Memento (val level: Int, val money: Int)
//存放存檔的物件,這個每個存檔都會覆蓋之前的記錄,如果要存多個檔,可使用List
class Caretaker{
var memento: Memento? = null
}

Client

遊戲開始的角色設定

val player = GamePlayer()
player.level = 2
player.money = 300
println("一開始角色的等級:${player.level}, 金錢:${player.money}")

存檔,透過Caretaker存檔。

//存檔
val caretaker = Caretaker()
caretaker.memento = player.createMemento()

角色死掉了,將角色等級、金錢歸零

//死掉了,等級、金錢歸0
player.level = 0
player.money = 0
println("角色死掉了,等級:${player.level}, 金錢:${player.money}")

要執行復原,一樣要透過Caretaker取出存檔

//執行復原,取出存檔
player.setMemento(caretaker.memento!!)
println("角色復原了,等級:${player.level}, 金錢:${player.money}")

執行結果

一開始角色的等級:2, 金錢:300
角色死掉了,等級:0, 金錢:0
角色復原了,等級:2, 金錢:300

總結一下,Caretaker主要用來管理Memento 物件,也就是儲檔、取檔都透過Caretaker。而Memento則是用來保留 Originator 內部狀態,也就是要儲存的遊戲者的等級及金錢。Originator則是遊戲的角色狀態。

備忘錄模式除了儲存狀態也能儲存演算法,例如在玩象棋時的回上一步功能,我們可能就會在每一步儲存單一棋子移動的方式,而不是將當下所有的棋子狀態儲存下來。

在使用備忘錄模式時,也要考慮到時效性問題、及如果儲存的資料太多會有記憶體問題。

下一篇:Design Pattern Decorator

--

--