備忘錄模式的定義 定義: 在不破壞封裝性的前提下, 捕獲一個對象的內部狀態, 併在該對象之外保存這個狀態. 這樣以後就可將該對象回覆到原先保存的狀態 通俗的說, 就是記錄下類的當前狀態, 當需要的時候恢復 類圖如下: 其中各角色如下: 發起人角色代碼: 備忘錄角色代碼: 備忘錄管理員角色代碼: 場景 ...
備忘錄模式的定義
定義: 在不破壞封裝性的前提下, 捕獲一個對象的內部狀態, 併在該對象之外保存這個狀態. 這樣以後就可將該對象回覆到原先保存的狀態
通俗的說, 就是記錄下類的當前狀態, 當需要的時候恢復
類圖如下:
其中各角色如下:
- Originator 發起人角色: 記錄當前時刻的內部狀態, 負責定義哪些屬於備份範圍的狀態, 負責創建和恢復備忘錄數據
- Memento 備忘錄角色: 負責存儲 發起人對象的內部狀態, 在需要的時候提供發起人需要的內部狀態
- Cartetaker 備忘錄管理員角色: 對備忘錄進行管理、保存和提供備忘錄.
發起人角色代碼:
備忘錄角色代碼:
備忘錄管理員角色代碼:
場景類:
備忘錄模式的應用
備忘錄模式的使用場景:
- 需要保存和恢複數據的相關狀態場景
- 提供一個可回滾的操作
- 需要監控的副本場景中. 例如要監控一個對象的屬性, 但是監控又不應該作為系統的主業務來調用, 即使出現監控不准也影響不大, 因此一般做法是備份一個主線程中的對象
- 資料庫連接的事務管理就是用的備忘錄模式
備忘錄模式的註意事項:
- 備忘錄的生命期. 備忘錄創建出來就要在"最近"的 代碼中使用, 要主動管理它的生命周期,建立就要使用, 不適用就要立即刪除其引用, 等待垃圾回收期對他的回收處理
- 備忘錄的性能. 不要再頻繁建立備份的場景中使用別忘路模式, 原因如下: 一是控制不了備忘錄建立的對象數量. 二是大對象的建立是要消耗資源的, 系統的性能需要考慮.
備忘錄模式的擴展
1.clone方式的備忘錄
通過 clone 獲取當前對象的副本, 在需要的時候進行還原, 這樣就不需要備忘錄對象了, 當然也就不需要備忘錄管理角色了, 修改後的代碼如下:
程式精簡了很多.
2.多狀態的備忘錄模式
當類的狀態有很多個的時候, 將狀態一個一個寫當然不是一個好辦法, 那樣要寫大量的代碼, 還容易犯錯誤.
使用 clone 方式是可以解決的, 下麵使用數據技術來解決, 實現一個JavaBean對象的所有狀態的備份和還原
通過一個工具類, 將JavaBean對象的所有屬性都保存到一個HashMap中.
發起人角色代碼:
工具類代碼:
當然,有很多工具已經提供了, 比如Apache的工具集commons等
備忘錄代碼:
備忘錄管理員角色代碼不變.
這樣, 不管有多少狀態都沒問題了
3.多備份的備忘錄
有時需要有多份備份, 我們先來說一個名詞, 檢查點, 也就是在備份的時候做的戳記, 系統級的備份一般是時間戳, 我們愁緒的檢查點呢?一般是一個有意義的字元串.
我們只要把通用代碼的備忘錄管理員修改一下就可以了, 代碼如下:
這時要註意記憶體溢出的問題, 以為備份一旦產生就裝入記憶體, 沒有任何銷毀的一項, 這是很危險的.
4.封裝得更好一點
有時, 我們要保證備份不能被篡改, 要保證其他人沒有備忘錄的閱讀許可權, 只能是發起人可讀, 這怎麼辦呢?
我們將備忘錄設成發起人的內部類, 讓備忘錄的方法均為私有,這樣,就只有發起人可以調用備忘錄的方法了, 那備忘錄管理者如何獲取備忘錄呢? 只要讓備忘錄實現一個外部的空介面即可.
發起人代碼如下:
內置類全都是private的訪問許可權, 除了發起人外,別人休想訪問到, 與其他類的關聯關係通過公共介面實現
備忘錄的空介面:
備忘錄管理者:
在這裡, 使用了一個新的設計方法: 雙介面設計, 我們的一個類可以實現多個介面, 在系統設計時, 如果考慮對象的安全問題, 則可以提供兩個介面, 一個是業務的正常介面, 實現必要的業務邏輯,叫做寬介面; 另外一個是一個空介面, 什麼方法都沒有, 其目的是提供給子系統外的模塊訪問, 比如容器對象,這個叫做窄介面, 由於窄介面中沒有提供任何操縱數據的方法, 因此相對來說比較安全
在設計的時候不要使用資料庫的臨時表作為緩存備份數據了, 雖然是一個簡單的辦法,但是它加大了資料庫操作的頻繁度, 把壓力下放到資料庫了, 最好的解決辦法就是使用備忘錄模式.