三十、備忘錄模式

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. 優缺點

  • 優點:

    • 狀態恢復機制,使得用戶可以方便地回到一個特定的歷史步驟,當新的狀態無效或者存在問題時,可以使用暫時存儲起來的備忘錄將狀態復原.
    • 信息的封裝,一個備忘錄對象是一種原發器對象狀態的表示,不會被其他代碼所改動。備忘錄保存了原發器的狀態,采用列表、堆棧等集合來存儲備忘錄對象可以實現多次撤銷操作.
  • 缺點:

    • 資源消耗過大,如果需要保存的原發器類的成員變量太多,就不可避免需要占用大量的存儲空間,每保存一次對象的狀態都需要消耗一定的系統資源.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容