基本理解
這個模式有三個關鍵角色:原發器(Originator)、備忘錄(Memento)、看管人(caretaker)。三者的基本關系是:原發器創建一個包含其狀態的備忘錄,并傳給看管人??垂苋瞬恢廊绾闻c備忘錄交互,但會把備忘錄放在一個安全之處保管好。
備忘錄(Memento):在 不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可以將該對象回復到原先保存的狀態。
Originator(發起人):負責創建一個備忘錄,用以記錄當前時刻它的內部狀態,并且可使用恢復備忘錄內部狀態。Originator可根據需要決定Memento存儲Originator的哪些內部狀態。
Memento(備忘錄):負責存儲Originator對象的內部狀態,并可防止Originator以外的其他對象訪問備忘錄。備忘錄有兩個接口,CareTaker
只能看到備忘錄的窄接口,它只能將備忘錄傳給其他對象。originator能夠看到一個寬接口,允許它訪問返回到先前狀態所需的所有數據。
Caretaker(管理者):負責保存好備忘錄,不能對備忘錄的內容進行操作或檢查。
就是把要保存的細節給封裝在了Memento中,哪一天要更改保存的細節也不用影響客戶端了。
備忘錄使用場合
備忘錄模式比較適用于功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性中的一小部分時,Orignator可以根據保存的Memento信息還原到前一狀態。
如果在某個系統中使用命令模式時,需要實現命令的撤銷功能,那么命令模式可以使用備忘錄模式來存儲撤銷操作的狀態。有的時候一些對象的內部信息必須要保存在對象以外的地方,但是必須要由對象自己讀取,這時,使用備忘錄可以把復雜的對象內部信息對其他的對象屏蔽起來。
用于獲取狀態的接口會暴露實現接口,需要將其屏蔽起來。
它一般應用于游戲、文字處理程序的設計中,這種程序需要保存當前上下文的復雜狀態的快照并在以后恢復處理。
作用
當角色的狀態改變時,有可能這個狀態無效,這時候就可以使用暫時存儲起來的備忘錄將狀態復原。
Cocoa Touch框架中的備忘錄模式
Cocoa Touch框架在歸檔、屬性列表序列化和核心數據采用了備忘錄模式。
Cocoa的歸檔是對對象以及其屬性還有同其他對象間的關系進行編碼,形成一個文檔,該文檔既可保存與文件系統中,也可在進程或網絡間傳送。對象與其他對象的關系被看做對象圖的網絡。
歸檔過程把對象保存為一種與架構無關的字節流,保持對象的標識以及對象之間的關系。對象的類型也同數據一起保存。從字節流解碼出來的對象通常用于對象編碼時相同的類進行實例化。使用NSCoder的具體類NSKeyedArchiver和NSKeyedUnarchiver,使用基于鍵的歸檔技術,被編碼與解碼的對象必須遵守NSCoding協議并實現以下方法:
實例
添加下面兩個方法到 ViewController.m 文件:
- (void)loadPreviousState
{
currentAlbumIndex = [[NSUserDefaults standardUserDefaults] integerForKey@“currentAlbumIndex”];
[self showDataForAlbumAtIndex:currentAlbumIndex];
}
loadPreviousState 加載這之前存儲的專輯索引。這不是備忘錄模式的全部,不過你已經達到目的了。
現在,在 ViewController.m 里,滾動視圖初始化之前,在 viewDidLoad 里添加下面一行:
在 viewDidLoad: 最后面添加下面一行
現在,添加下面代碼:
構建和運行你的 app,點擊到一個專輯,用 Command+Shift+H(如果你使用的是模擬器的話) 將程序在后臺運行,然后關掉 app。重啟 app,檢查之前選擇的專輯是不是居中顯示:
專輯數據看起來是對的,但是正確的專輯封面確沒有居中,哪出問題了?
這就是可選方法 initialViewIndexForHorizontalScroller 的用處!因為這個方法沒有被委托執行,ViewController 在這種情況下總是會顯示默認的第一個專輯封面。
修復這個問題,在 ViewController.m 中添加如下代碼:
重新運行你的 app,滾動專輯封面,關閉 app,然后重啟確保問題已經得到解決:
如果你查看 PersistencyManger 的初始化方法,你會注意到專輯的數據是一種硬編碼,PersistencyManger 每次創建,數據也會重復創建一次。有沒有一種更好的方法當專輯列表被創建的時候就存儲它們呢。那么如何把專輯數據存儲到文件里呢?
一種選擇就是循環訪問 Album 的屬性,然后把它存儲在一個 plist 文件里,當需要它們的時候重新創建一個 Album 的實例。這不是最好的選擇,這需要你在每一個類里根據不同的數據或屬性寫特定的代碼。例子,如果稍后你需要一個電影的類,里面有一些不同的屬性,存儲和加載這些數據你就需要寫一些新的代碼。
此外,你不能在每一個類的實例里存儲私有變量,因為他們是不可訪問的外部類。這就是為什么蘋果要創建歸檔 (Archiving) 機制。
新聞熱點
疑難解答