23種設計模式之備忘錄模式

備忘錄模式的定義

定義: 在不破壞封裝性的前提下, 捕獲一個對象的內部狀態, 並在該對象之外保存這個狀態. 這樣以後就可將該對象回覆到原先保存的狀態

通俗的說, 就是記錄下類的當前狀態, 當需要的時候恢復

類圖如下:

23種設計模式之備忘錄模式

其中各角色如下:

  1. Originator 發起人角色: 記錄當前時刻的內部狀態, 負責定義哪些屬於備份範圍的狀態, 負責創建和恢復備忘錄數據
  2. Memento 備忘錄角色: 負責存儲 發起人對象的內部狀態, 在需要的時候提供發起人需要的內部狀態
  3. Cartetaker 備忘錄管理員角色: 對備忘錄進行管理、保存和提供備忘錄.

發起人角色代碼:

23種設計模式之備忘錄模式

備忘錄角色代碼:

23種設計模式之備忘錄模式

備忘錄管理員角色代碼:

23種設計模式之備忘錄模式

場景類:

23種設計模式之備忘錄模式

備忘錄模式的應用

備忘錄模式的使用場景:

  1. 需要保存和恢復數據的相關狀態場景
  2. 提供一個可回滾的操作
  3. 需要監控的副本場景中. 例如要監控一個對象的屬性, 但是監控又不應該作為系統的主業務來調用, 即使出現監控不準也影響不大, 因此一般做法是備份一個主線程中的對象
  4. 數據庫連接的事務管理就是用的備忘錄模式

備忘錄模式的注意事項:

  1. 備忘錄的生命期. 備忘錄創建出來就要在"最近"的 代碼中使用, 要主動管理它的生命週期,建立就要使用, 不適用就要立即刪除其引用, 等待垃圾回收期對他的回收處理
  2. 備忘錄的性能. 不要再頻繁建立備份的場景中使用別忘路模式, 原因如下: 一是控制不了備忘錄建立的對象數量. 二是大對象的建立是要消耗資源的, 系統的性能需要考慮.

備忘錄模式的擴展

1.clone方式的備忘錄

通過 clone 獲取當前對象的副本, 在需要的時候進行還原, 這樣就不需要備忘錄對象了, 當然也就不需要備忘錄管理角色了, 修改後的代碼如下:

23種設計模式之備忘錄模式

程序精簡了很多.

2.多狀態的備忘錄模式

當類的狀態有很多個的時候, 將狀態一個一個寫當然不是一個好辦法, 那樣要寫大量的代碼, 還容易犯錯誤.

使用 clone 方式是可以解決的, 下面使用數據技術來解決, 實現一個JavaBean對象的所有狀態的備份和還原

通過一個工具類, 將JavaBean對象的所有屬性都保存到一個HashMap中.

發起人角色代碼:

23種設計模式之備忘錄模式

工具類代碼:

23種設計模式之備忘錄模式

當然,有很多工具已經提供了, 比如Apache的工具集commons等

備忘錄代碼:

23種設計模式之備忘錄模式

備忘錄管理員角色代碼不變.

這樣, 不管有多少狀態都沒問題了

3.多備份的備忘錄

有時需要有多份備份, 我們先來說一個名詞, 檢查點, 也就是在備份的時候做的戳記, 系統級的備份一般是時間戳, 我們愁緒的檢查點呢?一般是一個有意義的字符串.

我們只要把通用代碼的備忘錄管理員修改一下就可以了, 代碼如下:

23種設計模式之備忘錄模式

這時要注意內存溢出的問題, 以為備份一旦產生就裝入內存, 沒有任何銷燬的一項, 這是很危險的.

4.封裝得更好一點

有時, 我們要保證備份不能被篡改, 要保證其他人沒有備忘錄的閱讀權限, 只能是發起人可讀, 這怎麼辦呢?

我們將備忘錄設成發起人的內部類, 讓備忘錄的方法均為私有,這樣,就只有發起人可以調用備忘錄的方法了, 那備忘錄管理者如何獲取備忘錄呢? 只要讓備忘錄實現一個外部的空接口即可.

發起人代碼如下:

23種設計模式之備忘錄模式

內置類全都是private的訪問權限, 除了發起人外,別人休想訪問到, 與其他類的關聯關係通過公共接口實現

備忘錄的空接口:

23種設計模式之備忘錄模式

備忘錄管理者:

23種設計模式之備忘錄模式

在這裡, 使用了一個新的設計方法: 雙接口設計, 我們的一個類可以實現多個接口, 在系統設計時, 如果考慮對象的安全問題, 則可以提供兩個接口, 一個是業務的正常接口, 實現必要的業務邏輯,叫做寬接口; 另外一個是一個空接口, 什麼方法都沒有, 其目的是提供給子系統外的模塊訪問, 比如容器對象,這個叫做窄接口, 由於窄接口中沒有提供任何操縱數據的方法, 因此相對來說比較安全


在設計的時候不要使用數據庫的臨時表作為緩存備份數據了, 雖然是一個簡單的辦法,但是它加大了數據庫操作的頻繁度, 把壓力下放到數據庫了, 最好的解決辦法就是使用備忘錄模式.


分享到:


相關文章: