天天看點

備忘錄模式

備忘錄模式其實就是給我們的應用程式一次撤銷的機會。使用過word的人肯定會知道偉大的“ctrl+z”,用過ps的人更是不會忘記,應該來說基本上所有的帶編輯功能的軟體毫無例外都提供了撤銷的功能,撤銷功能給了我們1次或n次傳回的機會,準确地說應該是恢複之前狀态的機會。我們自己開發的軟體有時候有需要撤銷的功能,比如在網絡通信中,常常會因為不可預知的錯誤就導緻程式出錯,這時候,要是能恢複到上一個正确的狀态就太好了,這樣可以省去不上功夫。我們今天要讨論的備忘錄模式就是用來解決這個問題的。

經典的備忘錄模式如下圖所示:

備忘錄模式

注:本圖來自《設計模式_基于c#的工程化實作及擴充》

      首先,還是讓我來解釋一下這幅圖的意思:originator(原發器)就是我們的業務模型,它本身可能有非常多的字段(或叫做變量)。一個字段的值發生了改變,我們可以認為originator的狀态就發生了變化。originator裡面有一個imemento類型的字段用來記錄狀态的變化(它相當于一個記事本,用來備忘的)。imemento聚合與caretaker,caretaker也就是負責人,用來決定什麼時候将imemento(備忘錄)對象中的狀态還原到originator(原發器)中。打個形象的比喻,originator就好比一個圖書館,圖書館裡面有很多書,每一本書都有接還狀态(後面我們會提到istate用來表示狀态),imemento就想到于圖書館管理者手中的接還本(或稱之為備忘錄),caretaker就相當于圖書館管理者,圖書館管理者(caretaker)儲存有一本(或n本)備忘錄。當一本書(假設是booka)借出去的時候,圖書館(originator)的booka的狀态(istate)就發生了變化,變成借出狀态。等到還書的時候,圖書館管理者(caretaker)再通過備忘錄(imemeto)對象将圖書館(originator)還原成原始的狀态。需要說明的是,這個比喻并不恰當,因為書的借出、歸還就兩種狀态,但是實際應用中,因為originator中的變量的取值範圍的大小,originator中的某一個變量可以有很多狀态,這時候才是備忘錄發揮作用的時候。

1、備忘錄模式裡面涉及到的類型有caretaker(負責人類型)、originator(原發器類型)、imemento(備忘錄類型)、istate(狀态類型),在下面的代碼中,我們将不會涉及到實際的caretaker類型。我們先定義狀态類型(istate),我們下面隻是單純地定義一個接口,實際開發過程中可以為istate接口定義一些方法、屬性。

備忘錄模式
備忘錄模式

2、定義原發器、備忘錄抽象基類

備忘錄模式
備忘錄模式
備忘錄模式
備忘錄模式

3、我們在定義業務邏輯中使用的備忘錄和原發器,有了前面的基礎,現在我們就好辦了。我們将要實作定定光标位置的軟體,在必要的時候,我們要将現在的坐标恢複到上一個光标的位置。我們将定義一個position類型來存儲光标的x、y軸數值(也就是狀态,是以position實作istate),用一個實體類型的originator(原發器)實作對光标的操作。

備忘錄模式
備忘錄模式
備忘錄模式
備忘錄模式

4、定義完了接口和抽象類,現在我們來看看如何實際地應用備忘錄模式

備忘錄模式
備忘錄模式

在上面代碼中,我們并沒有引入caretaker,而是直接在代碼中指定還原點(見紅色注釋),實際應用中可能要再建立一個caretaker類,以便在系統出現異常或者在某種特定的情況下對狀态進行還原。

     有同學會說,為了備份一個類裡面的一些狀态,有必要搞得這麼複雜嗎?還定義了istate、ioriginator、imemento三種接口,更恐怖的是還有對應的抽象基類和實體類。其實,這的确增加了需要代碼的複雜程度,如果需要備份的狀态幾乎不會發生變化,那麼其實簡單地在業務邏輯對象(originator)裡面增加一些字段或一個類簡單地記錄一下就行。但是如果原發器中有不同的狀态,我們有時候隻需要記錄其中一個變量的狀态或幾個變量的狀态,或者要記錄的狀态有時候會因為業務規則而發生改變,我們又不想讓這個改變影響太多的代碼,那麼如同以上代碼,我們将狀态和備忘錄抽象為isate和imemento,這樣就可以非常友善地對會變動的狀态進行調整。

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

轉載:http://www.cnblogs.com/kissazi2/p/3288404.html