|
一、引子
三、舉例 按照定義中的要求,備忘錄角色要保持完整的封裝。最好的情況便是:備忘錄角色只應該暴露操作內(nèi)部存儲屬性的的接口給“備忘發(fā)起角色”。而對于其他角色則 是不可見的。GOF在書中以C++為例進行了探討。但是在Java中沒有提供類似于C++中友元的概念。在Java中怎樣才能保持備忘錄角色的封裝呢? 下面對三種在Java中可保存封裝的方法進行探討。 第一種就是采用兩個不同的接口類來限制訪問權限。這兩個接口類中,一個提供比較完備的操作狀態(tài)的方法,我們稱它為寬接口;而另一個則可以只是一個標示, 我們稱它為窄接口。備忘錄角色要實現(xiàn)這兩個接口類。這樣對于“備忘發(fā)起角色”采用寬接口進行訪問,而對于其他的角色或者對象則采用窄接口進行訪問。 這種實現(xiàn)比較簡單,但是需要人為的進行規(guī)范約束——而這往往是沒有力度的。 第二種方法便很好的解決了第一種的缺陷:采用內(nèi)部類來控制訪問權限。將備忘錄角色作為“備忘發(fā)起角色”的一個私有內(nèi)部類。好處我不詳細解釋了,看看代碼吧就明白了。下面的代碼是一個完整的備忘錄模式的教學程序。它便采用了第二種方法來實現(xiàn)備忘錄模式。 還有一點值得指出的是,在下面的代碼中,對于客戶程序來說“備忘錄管理者角色”是不可見的,這樣簡化了客戶程序使用備忘錄模式的難度。下面采用“備忘發(fā)起角色”來調(diào)用訪問“備忘錄管理者角色”,也可以參考門面模式在客戶程序與備忘錄角色之間添加一個門面角色。 class Originator{![]() //這個是要保存的狀態(tài) private int state= 90; //保持一個“備忘錄管理者角色”的對象 private Caretaker c = new Caretaker(); //讀取備忘錄角色以恢復以前的狀態(tài) public void setMemento(){ Memento memento = (Memento)c.getMemento(); state = memento.getState(); System.out.println("the state is "+state+" now"); } //創(chuàng)建一個備忘錄角色,并將當前狀態(tài)屬性存入,托給“備忘錄管理者角色”存放。![]() public void createMemento(){ c.saveMemento(new Memento(state)); } //this is other business methods![]() //they maybe modify the attribute state ![]() public void modifyState4Test(int m){ state = m; System.out.println("the state is "+state+" now"); } ![]() //作為私有內(nèi)部類的備忘錄角色,它實現(xiàn)了窄接口,可以看到在第二種方法中寬接口已經(jīng)不再需要 //注意:里面的屬性和方法都是私有的![]() private class Memento implements MementoIF{ private int state ; private Memento(int state){ this.state = state ; }![]() private int getState(){ return state; } } }![]() //測試代碼——客戶程序![]() public class TestInnerClass{ public static void main(String[] args){ Originator o = new Originator(); o.createMemento(); o.modifyState4Test(80); o.setMemento(); } }![]() //窄接口![]() interface MementoIF{}![]() //“備忘錄管理者角色”![]() class Caretaker{ private MementoIF m ; public void saveMemento(MementoIF m){ this.m = m; } public MementoIF getMemento(){ return m; } }![]() 在上面 的教學代碼中,我們簡單的模擬了備忘錄模式的整個流程。在實際應用中,我們往往需要保存大量“備忘發(fā)起角色”的歷史狀態(tài)。這時就要對我們的“備忘錄管理者 角色”進行改造,最簡單的方式就是采用容器來按照順序存放備忘錄角色。這樣就可以很好的實現(xiàn)undo、redo功能了。 四、適用情況 從上面的討論可以看出,使用了備忘錄模式來實現(xiàn)保存對象的歷史狀態(tài)可以有效地保持封裝邊界。使用備忘錄可以避免暴露一些只應由“備忘發(fā)起角色”管理卻又必須存儲在“備忘發(fā)起角色”之外的信息。把“備忘發(fā)起角色”內(nèi)部信息對其他對象屏蔽起來, 從而保持了封裝邊界。 但是如果備份的“備忘發(fā)起角色”存在大量的信息或者創(chuàng)建、恢復操作非常頻繁,則可能造成很大的開銷。 GOF在《設計模式》中總結(jié)了使用備忘錄模式的前提: 1) 必須保存一個對象在某一個時刻的(部分)狀態(tài), 這樣以后需要時它才能恢復到先前的狀態(tài)。 2) 如果一個用接口來讓其它對象直接得到這些狀態(tài),將會暴露對象的實現(xiàn)細節(jié)并破壞對象的封裝性。 五、總結(jié) 介紹了怎樣來使用備忘錄模式實現(xiàn)存儲對象歷史狀態(tài)的功能,并對基于Java的實現(xiàn)進行了討論。歡迎大家指正。 |
|
|