《java與模式》學習系列——備忘錄模式

來源:互聯網
上載者:User

 

一、備忘錄(Memento)模式結構

備忘錄對象是一個用來儲存另外一個對象內部狀態的快照(snapshot)的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態捕捉住,並外部化,儲存起來,從而可以在將來適合的時候把這個對象還原到儲存起來的狀態。備忘錄模式常常與命令模式和迭代子模式一同使用。

其結構圖如下:

備忘錄模式涉及三個角色:備忘錄(Memento)角色、發起人(Originator)角色、負責人(Caretaker)角色。

備忘錄角色:

(1)      
將發起人對象的內部狀態儲存起來,備忘錄可以根據發起人對象的判斷來決定儲存多少發起人對象的內部狀態。

(2)      
備忘錄可以保護其內容不被發起人對象之外的任何對象所讀取。

備忘錄有兩個等效的介面:

窄介面:負責人(Caretaker)對象和其他除發起人對象之外的任何對象看到的是備忘錄的窄介面(narrow interface),這個窄介面只允許它把備忘錄對象傳給其他對象。

寬介面:與負責人對象看到的窄介面相反的是,發起人對象可以看到一個寬介面(wide interface),這個寬介面允許它讀取所有的資料,以便根據這些資料恢複這個發起人對象的內部狀態。

發起人角色:

(1)       建立一個含有當前的內部狀態的備忘錄對象。(2)使用備忘錄Object Storage Service其內部狀態。

負責人角色:

(1)       負責儲存備忘錄對象。(2)不檢查備忘錄對象的內容。

二、實現

雙重介面,就是同一個介面對某一個對象提供寬介面,而對另一些對象提供窄介面。根據程式設計語言的效能,雙重介面的實現方式有所不同。在C++中可以通過介面設定成私人同時將提供寬介面的對象設定為該介面的友元類即可。在java中則要通過把該介面的實現作為提供寬介面的對象的內部類來達到。

可以將Memento設成Originator類的內部類,從而將Memento對象封裝在Originator裡面;在外部提供一個標識介面MementorIF(Memento類實現MementorIF介面)給Caretaker以及其他對象。這樣,Originator類看到的是Mementor的所有介面,而Caretaker以及其他對象看到的僅僅是標識介面MementoIF所暴露出來的介面。

類圖如下:

代碼如下:

//發起人角色代碼<br />public class Originator {</p><p> private String state;<br /> public Originator(){}<br /> public MementoIF createMemento(){<br /> return new Memento(this.state);<br /> }<br /> //將發起人恢複到備忘錄對象記錄的狀態<br /> public void restoreMemento(MementoIF memento){<br /> Memento aMemento = (Memento)memento;<br /> this.setState(aMemento.getState());<br /> }<br /> public String getState(){<br /> return this.state;<br /> }<br /> public void setState(String state){<br /> this.state = state;<br /> System.out.println("state="+state);<br /> }<br /> //內部成員類,備忘錄<br /> protected class Memento implements MementoIF{<br /> private String savedState;<br /> private Memento(String someState){<br /> savedState = someState;<br /> }<br /> private void setState(String someState){<br /> savedState = someState;<br /> }<br /> private String getState(){<br /> return savedState;<br /> }<br /> }<br />}<br />//負責人角色代碼<br />public class Caretaker {</p><p> private MementoIF memento;<br /> public MementoIF retrieveMemento(){<br /> return this.memento;<br /> }<br /> public void saveMemento(MementoIF memento){<br /> this.memento = memento;<br /> }<br />}<br />//用戶端代碼<br />public class Client {<br /> private static Originator o = new Originator();<br /> private static Caretaker c = new Caretaker();<br /> public static void main(String []args){<br /> o.setState("on");<br /> //調用發起人角色的createMemento()方法,建立一個備忘錄對象將這個狀態儲存起來。將備忘錄Object Storage Service到負責人對象中去。這樣負責人並不知道具體的備忘錄,而只知道是MementoIF類型,這就是窄介面。<br /> c.saveMemento(o.createMemento());</p><p> o.setState("Off");<br /> //將備忘錄對象從負責人對象中取出。將發起人對象的狀態恢複成備忘錄對象所儲存起來的狀態,即”On”狀態。<br /> o.restoreMemento(c.retrieveMemento());<br /> }<br />} 

三、備忘錄模式在Java中的應用

J2EE架構中備忘錄模式的應用

Java引擎提供Session對象,可以彌補HTTP協議的無狀態缺點,儲存使用者的狀態。當一個新的網路使用者調用一張JSP網頁或者Servlet時,Servlet引擎會建立一個對應於這個使用者的Session對象,具體的技術細節可能是向用戶端瀏覽器發送一個含有Session ID的Cookie,或者使用URL改寫技術將Session ID 包括在URL中等。在一段有效時間裡,同一個瀏覽器可以反覆訪問伺服器,而Servlet引擎便可以使用這個Session ID來判斷來訪者應當與哪一個Session對象對應。Session和Cookie的使用都是備忘錄模式,如所示:

四、備忘錄模式的優缺點

優點:

1、 
有時一些發起人對象的內部資訊必須儲存在發起人對象以外的地方,但是必須要由發起人對象自己讀取。這時,使用備忘錄可以把複雜的發起人內部資訊對其他的對象屏弊起來,從而可以恰當地保持封裝的邊界。

2、 
本模式簡化了發起人類,發起人不再需要管理和儲存其內部狀態的一個個版本,用戶端可以自行管理它們所需要的這些狀態的版本。

3、 
當發起人角色的狀態改變的時候,有可能這個狀態無效,這時候就可以使用暫時儲存起來的備忘錄將狀態複原。

缺點:

1、 
如果發起人角色的狀態需要完整地儲存到備忘錄對象中,那麼在資源消耗上面備忘錄對象會很昂貴。

2、 
當負責人角色將一個備忘錄儲存起來的時候,負責人可能並不知道這個狀態會佔用多大的儲存空間,從而無法提醒使用者一個操作是否會昂貴。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.