三十、備忘錄模式

1. 何為備忘錄模式

備忘錄模式(memento)是指在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),這樣以后就可以將該對(duì)象恢復(fù)到原先保存的狀態(tài)。

這個(gè)模式有三個(gè)關(guān)鍵角色:原發(fā)器(Originator)、備忘錄(Memento)和看管人(caretaker)。其思想非常簡(jiǎn)單,原發(fā)器創(chuàng)建一個(gè)包含其狀態(tài)的備忘錄,并傳給看管人。看管人不知道如何與備忘錄交互,但會(huì)把備忘錄放在安全之處保管好。它們的靜態(tài)關(guān)系如圖1-1所示:

圖1-1 備忘錄模式結(jié)構(gòu)的類圖

當(dāng)看管人請(qǐng)求Originator對(duì)象保存其狀態(tài)時(shí),Originator對(duì)象將使用其內(nèi)部狀態(tài)創(chuàng)建一個(gè)新的Memento實(shí)例。然后看管人保管Memento實(shí)例,或者把它保存到文件系統(tǒng),一段時(shí)間后再把它傳回給Originator對(duì)象。Originator對(duì)象不知道這個(gè)Memento對(duì)象將如何被保存??垂苋艘膊恢繫emento對(duì)象里是什么。圖1-2中的時(shí)序圖解釋了他們之間的交互過程。

圖1-2 備忘錄模式的時(shí)序圖

這個(gè)設(shè)計(jì)的關(guān)鍵是維持Memento對(duì)象的私有性,只讓Originator對(duì)象訪問保存在Memento對(duì)象的內(nèi)部狀態(tài)(即Originator過去的內(nèi)部狀態(tài))。Memento類應(yīng)該有兩個(gè)接口:一個(gè)寬接口,給Originator用;一個(gè)窄接口,給其它對(duì)象用。上面圖中的setState:、 state和init方法應(yīng)該定義為私有,不讓Originator和Memento以外的對(duì)象使用。

2. 應(yīng)用場(chǎng)景及代碼實(shí)現(xiàn)

一般來說滿足一下兩個(gè)條件時(shí),應(yīng)當(dāng)考慮使用這一模式:

  • 需要保存一個(gè)對(duì)象(或部分)在某一個(gè)時(shí)刻的狀態(tài),這樣以后就可以恢復(fù)到先前的狀態(tài);
  • 用于獲取狀態(tài)的接口會(huì)暴露實(shí)現(xiàn)的細(xì)節(jié),需要將其隱藏起來。

備忘錄模式在棋類游戲(悔棋)、普通軟件(撤銷操作)、數(shù)據(jù)庫軟件(事物管理的回滾操作)和Photoshop軟件中體現(xiàn)較多。這里以游戲存檔為例:

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("當(dāng)前游戲的模式:\(game.pattern)---游戲的進(jìn)度:\(game.progress)")

let caretaker: CareTaker = CareTaker()
caretaker.memento = game.saveMemento()

game.progress = 0.5

print("當(dāng)前游戲的模式:\(game.pattern)---游戲的進(jìn)度:\(game.progress)")

print("備份游戲的模式:\(caretaker.memento!.pattern)---游戲的進(jìn)度:\(caretaker.memento!.progress)")

運(yùn)行結(jié)果:

當(dāng)前游戲的模式:1V1---游戲的進(jìn)度:0.2
當(dāng)前游戲的模式:1V1---游戲的進(jìn)度:0.5
備份游戲的模式:1V1---游戲的進(jìn)度:0.2

3. 優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):

    • 狀態(tài)恢復(fù)機(jī)制,使得用戶可以方便地回到一個(gè)特定的歷史步驟,當(dāng)新的狀態(tài)無效或者存在問題時(shí),可以使用暫時(shí)存儲(chǔ)起來的備忘錄將狀態(tài)復(fù)原.
    • 信息的封裝,一個(gè)備忘錄對(duì)象是一種原發(fā)器對(duì)象狀態(tài)的表示,不會(huì)被其他代碼所改動(dòng)。備忘錄保存了原發(fā)器的狀態(tài),采用列表、堆棧等集合來存儲(chǔ)備忘錄對(duì)象可以實(shí)現(xiàn)多次撤銷操作.
  • 缺點(diǎn):

    • 資源消耗過大,如果需要保存的原發(fā)器類的成員變量太多,就不可避免需要占用大量的存儲(chǔ)空間,每保存一次對(duì)象的狀態(tài)都需要消耗一定的系統(tǒng)資源.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 場(chǎng)景問題# 1.1 開發(fā)仿真系統(tǒng)## 考慮這樣一個(gè)仿真應(yīng)用,功能是:模擬運(yùn)行針對(duì)某個(gè)具體問題的多個(gè)解決方案,記...
    七寸知架構(gòu)閱讀 2,248評(píng)論 1 50
  • 定義 備忘錄模式又叫做快照模式(Snapshot Pattern)或Token模式,是對(duì)象的行為模式。 備忘錄對(duì)象...
    步積閱讀 3,118評(píng)論 0 2
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,075評(píng)論 1 15
  • 面向?qū)ο蟮牧笤瓌t 單一職責(zé)原則 所謂職責(zé)是指類變化的原因。如果一個(gè)類有多于一個(gè)的動(dòng)機(jī)被改變,那么這個(gè)類就具有多于...
    JxMY閱讀 1,017評(píng)論 1 3
  • <center>Activity</center> Activity的管理基于棧結(jié)構(gòu), 有焦點(diǎn)激活狀態(tài)的的只是棧頂...
    Yzlong閱讀 273評(píng)論 0 0

友情鏈接更多精彩內(nèi)容