[設計模式學以致用]備忘錄模式

[格物致知|深入淺出|學以致用]

1. 定義

所謂備忘錄模式,就是在不破壞封閉的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣以後就可將該對象恢復到原先保存的狀態。

2. 格物

對於備忘錄模式,有幾個點需要注意:

  • 不破壞封閉
  • 對象的內部狀態
  • 在該對象之外

這三個要點是從備忘錄模式的定義中提煉出來的,但如果要更容易的理解,應該把它們的順序顛倒一下。如下:

  1. 在該對象之外
  2. 對象的內部狀態
  3. 不破壞封閉

下面我們來依次分析一下這幾個要點。

2.1. 在該對象之外

這個點其實是要求將數據模型類和數據的保存操作解耦合,不由該對象自己進行數據的持久化,以免具體的保存邏輯出現變動時而改動該類的實現。
這個要點其實是其他設計模式和原則的要求。

2.2. 對象的內部狀態

衆所周知,在面向對象概念的類定義中,存在私有變量和公有變量之分,而備忘錄模式定義中所強調的“對象的內部狀態”應該就是指類似的私有變量。對象的內部狀態只是跟對象自己的行爲有關,所以並沒有開放給其他類的實例訪問。
但是如果想要保存某一個狀態下的完整對象,私有變量的值也是需要保存下來的。
這個要點是該設計模式的前提。

2.3. 不破壞封閉

這個要點是該設計模式的精髓所在,有了前兩個的鋪墊,那這個要點就很容易理解了。

問題:在一個對象之外對該對象的內部私有變量並進行保存。
一般遇到這樣的問題,常用的處理方法有兩種:
第一,違背要點一,改由該對象自己進行數據保存,並新增一個公用方法給外部調用;
第二,違背要點二,將類的私有變量改爲公有變量,讓外部的對象直接訪問,並進行保存。
看到這裏有人不禁要問,上面這兩個方法已經違背了這個設計模式定義的前提,怎麼叫解決方法呢?作者你難道在講笑話?
其實不然,現實的編程工作中有這無數的遷就和妥協,而上面這兩個方法就是現實的寫照~(此處應該有憨笑emoji)
或許Gof爲了避免大家使用這兩個取巧的辦法,所以加了第三個要點作爲強調——“不破壞封閉”。
這樣就要求我們直面這個貌似悖論的問題:如何在對象外保存對象的私有變量?

3.致知

有了對前面三個要點的分析,那麼現狀就很明瞭了。
對象外部需要保存對象內部變量,兩者無法直接溝通,那麼必然需要一箇中間產物來作爲中介。即對象將內部變量放在中間產物中,然後交由對象外部,對象外部將該中間產物進行保存。
而數據恢復時,對象外部先讀取到中間產物,然後將中間產物交給對象,對象自己恢復中間產物中的數據。

這樣一來就完全滿足了模式定義中的三個要點,沒有破壞封閉,在對象外部保存對象的內部變量。
而這裏所謂的中間產物,便是該模式的名稱——備忘錄。

備忘錄模式中的三個角色分別爲發起人Originator、備忘錄Memento、管理者Caretaker。這些角色分類充分體現了設計模式的單一職責原則,發起人負責業務功能,向業務系統提供數據;備忘錄只負責爲保存功能提供組織好的數據;管理者負責具體的保存功能。
備忘錄爲了滿足信息的封閉,即部分數據向發起人開放,而不向管理者開放,正常來說需要兩個接口,這便是常說的寬接口和窄接口。寬接口提供完整的數據訪問,以便發起人能夠據此恢復數據。而管理者只需要保存備忘錄本身,所以只需要一個最小的窄接口即可。

4.致用

根據備忘錄模式的定義,我們很容易便可以找到該模式適用的第一個場景——1.需要在對象外保存對象的內部變量時。
不過設計模式的意義在於舉一反三,所以其可以應用的外延大多超過了其定義。
即便現在的應用場景不是保存對象的內部變量,而是保存對象的公開變量,從迪米特法則來看,也不應該由管理者直接進行保存,而應該由發起人自己保存。但發起人自己保存,又違反了單一職責原則。若是由管理者直接將發起人保存,那樣當需要保存發起人的部分變量時,這樣的功能又有些冗餘。如此一來,便又回到了備忘錄模式上——2.需要保存對象的部分變量時。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章