設計模式——裝飾者/策略/觀察者模式


裝飾者模式

裝飾者模式:簡單的理解就是在原有對象上包裝一層附件動作,且保持包裝完后的對象與被包裝者屬於同一個類族,但是額外附加了該包裝類所特定的動作。

其關鍵點有:

  1. 包裝類對象HAS-A被包裝對象;
  2. 包裝類與被被包裝對象屬於同一個類族,即都有相同的超類型;
  3. 包裝可以嵌套/可以被多次包裝,即某被包裝者被包裝類A包裝之后產生的對象還可以繼續被其他包裝類包裝,包括上一層包裝類A

包裝模式所體現的“對擴展開放,對修改關閉”原則:

  1. 對擴展開放:通過包裝,原被包裝對象有了包裝類指定的擴展行為,可以用於原被包裝對象的場合(當然前提是那是基於接口設計的代碼)
  2. 對修改關閉:不用修改已有的代碼即可以實現功能的擴展。

使用包裝者模式與使用繼承的區別:使用包裝者模式可以動態的添加行為,使用繼承則是靜態的,是編譯時確定的。假設使用繼承模式,則必須對每一種可能存在的行為組合都寫一個專門的類來表示,即你的代碼能夠表示的行為組合的種類是由你設計的類決定的,客戶無法得到你設計之外的組合模式;而使用包裝者模式,你只需把所有可能的基本行為寫好,而這些行為怎么去組合,則完全由客戶根據自己的需要決定。

裝飾者模型的缺點:

  1. 可能會加入大量的小類或者存在很多的對象;
  2. 對於某些依賴於特定類型的代碼的,包裝者就會失效。

類模型:

 

策略模式

策略模式:定義算法族,分別封裝起來,讓他們之間可以互相替換,以讓算法的變化獨立於使用算法的客戶代碼。其出發宗旨就是:封裝變的部分!

要點:

  1. 定義多個算法,即多個實現方案;
  2. 各個算法之間可以替換,一般實現方式是讓所有算法實現某個接口,且在客戶代碼中針對接口編程;
  3. 算法的變化獨立於使用者:可以更改算法的實現代碼,但是使用者代碼確不用任何更改;可以設置使用者使用的具體實現算法

使用案例:假使定義一個Coder類,不同的Coder有不同的writeBolg方式,那么根據策略模式的思路,其類模型如下:還可以在Coder中添加set(WriteBlog)方法以動態的設置策略

優勢:假使有這么一個需求:有CoderA,COderB,CoderC,COderD四種Coder,其中A,B使用InCnblog,C,D使用InCsdn,那么假使使用繼承來解決,那么可能分別需要在CoderA,COderB中以InCnblog的方式重寫writeBlog,在CoderC,COderD中以InCsdn的方式重寫writeBlog,顯然,產生了重復的代碼。而且,當以后以InCsdn的實現方案變了,那么就需要在CD兩個類中去維護。再進一步,如果CoderB突然想以InCsdn方式寫博客了,繼承的方式可能就難以應付。而使用策略模式則可以很好的解決這些問題。

觀察者模式

觀察者模式:定義對象之間的一對多依賴,當一個對象改變狀態時,它所有的依賴者都會收到通知並自動更新。

要點:

  1. 一對多:避免多個對象控制同一個數據
  2. 可注冊可移除:讓被觀察者與觀察者之間的耦合盡量最低

簡單的觀察者模型:

  1. 消息更新的方式有兩種。一種是pull,即在Oberver中調用getData方法獲取自己想要的數據,方便按需索取;一種是push,即在update方法中(此時update則必須有參數),把所有的數據類型都一次性傳給Oberver,比較方便,也是用的更多的方式;
  2. 為什么在observer要有subject的引用:用於移除自己的注冊;
  3. 不要依賴於觀察者被通知的順序:由於我們設計的目的就是松耦合,所以如果subject做了某些改變導致通知的順序變了,假如在obsever中存在某種對通知順序的依賴,那么observer則也必須做出相應的改變以適應subject的改變,這樣是不符合設計初衷的
  4. 在java.util.Observable提供觀察者模型,http://www.android-doc.com/reference/java/util/Observable.html, 需要注意的事,必須先調用setChanged()才會通知才會有效,因為在notifyObservers的方法中,要先檢查changed為true才會通知obervers。這樣的設計可以讓通知模式有更多彈性,比如對於氣象站的源數據數據,可能是實時更新,但是對於觀察者來說可能每小時更新一次就夠了,那么就可以每一小時調用一次setChanged().

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com