<大話設計模式>本教程說明及著作權聲明
國士工作室是一支專註於Android平台企業級應用開發的技術團隊,致力於做中國最棒的Android應用程式開發機構,提供最棒的Android企業級應用開發培訓服務。
企業培訓和開發合作官方連絡方式:
電話:18610086859
Email:hiheartfirst@gmail.com
QQ:1740415547
國士工作室 有你更美好!
l 該文檔參考和使用了網路上的免費開放的圖片和內容,並以免費開放的方式發布,希望為移動互連網和智能手機時代貢獻綿薄之力!可以隨意轉載,但不得使用該文檔謀利。
l 如果對該文檔有任何疑問或者建議,請進入官方部落格
http://www.cnblogs.com/guoshiandroid/留言或者直接與國士工作室聯絡(後附連絡方式),我們會謹慎參考您的建議並根據需要對本文檔進行修改,以造福更多開發人員!
l 《大話設計模式》的最新及完整內容會在國士工作室官方部落格定期更新,請訪問國士工作室部落格
http://www.cnblogs.com/guoshiandroid/擷取更多更新內容。
裝飾模式 見MM的家長
裝飾模式應用情境舉例:
“K哥,我老婆說要我和她一塊回去見家長,她還說她父親大人主動要和我多喝幾杯,我該怎麼辦啊?”GG很著急的對自己的好朋友K說道,“暈,老婆?你們發展的也太快了吧,不過還是恭喜喔”K帶著調侃的語氣說道,“不過要去見家長這事情確實需要謹慎的”,“按照慣例,既然對方主動的提出邀請,而且她父親大人都說要和你小子多喝幾杯,這是非去不可的了;其實也沒什麼,有些心理準備就行了,我們相信GG!”K繼續調侃的說道,“不過,要注意形象:-O”,“具體要以什麼形象出現呢?”GG問道,“這個你問我?我問誰啊?乾脆我代你去算了”,“我是說認真的啊”GG有些著急,“這主要看你要給對方什麼印象了啊”K有些認真的說道,“具體什麼印象呢?”GG問道,“一般而言,首要的是必須讓對方父母知道你很愛他們的女兒;其次:年輕人都是要有活力的,開朗而陽光;再次:要給對方家長自己很上進的印象:-O”K一臉認真的說道,“哈哈,K哥就是K哥,果然不愧是情場老大啊”,“那我具體應該穿什麼呢?”GG接著問道,“牛仔褲是一定要穿的,你平時穿的那條天藍色牛仔褲就很棒,至於上衣忙,你現在白色的襯衫就很不錯的,別忘了頭髮要乾淨,牙齒要潔白,盡量的保持你單純的傻傻的笑容^_^”,GG這麼麻煩的問題被K三加五除二解決掉,GG興奮的說:“老大,我愛死啦!”
裝飾模式解釋:
裝飾( Decorator )模式又叫做封裝(Wrapper)模式。通過一種對用戶端透明的方式來擴充項物件的功能,是繼承關係的一個替換方案。
英文定義為:Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending
functionality.
裝飾模式的UML圖:
建造者模式涉及以下的角色:
抽象組件(Component)角色: 一個抽象介面,是被裝飾類和裝飾類的父介面。
具體組件(Concrete Component)角色:為抽象組件的實作類別。
抽象裝飾(Decorator)角色:包含一個組件的引用,並定義了與抽象組件一致的介面。
具體裝飾(Concrete Decorator)角色:為抽象裝飾角色的實作類別。負責具體的裝飾。
裝飾模式的UML圖如下所示:
裝飾模式深入分析:
裝飾模式以一種對客服端透明的方式動態對對象增加功能,是繼承的一種很好的替代方案。
繼承是一種物件導向語言特有的而且也是一種非常容易被濫用的複用和擴充的手段。繼承關係必須首先符合分類學意義上的基類和子類的感謝,其次繼承的子類必須針對基類進行屬性或者行為的擴充。繼承使得修改或者擴充基類比較容易;但是繼承也有很多不足,首先繼承破壞了封裝,因為繼承講基類的實現細節暴露給了子類,其次,如果基類的實現發生了變化,那麼子類也就會跟著,這時候我們就不得不改變子類的行為,來適應基類的改變。最後從基類繼承而來的實現都是靜態,不可能在運行期(runtime)發生改變,這就使得相應的系統缺乏足夠的靈活性。
由於以上諸多的原因,一般盡量是不使用繼承來給對象增加功能,此時,裝飾模式就是一種更好的選擇了,這是因為:首先,裝飾模式對用戶端而言是透明,用戶端根本感覺不到是原始對象還是被裝飾過的對象,也就是說裝飾模式對用戶端而言是透明的;其次裝飾者和被裝飾對象擁有共同一致的介面,而且裝飾者採用對被裝飾類的引用的方式使用被裝飾對象,這就使得裝飾對象可以無限制的動態裝飾被裝飾對象;最後裝飾對象並不知道被裝飾對象是否被裝飾過,這就使得面對任何被裝飾的對象,裝飾者都可以採用一致的方式去處理。
裝飾模式使用情境分析及代碼實現:
在上面的使用情境中,GG要去接受MM家長的檢查,要考慮如何打扮自己。首先,GG本身是一個具體的組件;其次穿上牛仔褲的GG依舊是GG,只不過是被牛仔褲裝飾了一下而已,成了牛仔男了;最後,上衣再穿上一件襯衫,這次是在牛仔男的基礎上進行了進一步的裝飾,此時一個陽光帥氣的美男子誕生了,但是從本質上講,還是那個GG^_^
UML模型圖如下所示:
建立一個組件介面:
package com.diermeng.designPattern.Decorator; /* * 組件的介面 */ public interface Person { public void show(); public void noDecorator(); } |
建立基本的裝飾抽象類別基類:
package com.diermeng.designPattern.Decorator; /* * 基本的裝飾抽象類別基類 */ public abstract class PersonDecorator implements Person{ private Person person; public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public PersonDecorator(Person person) { this.person = person; } public abstract void show(); } |
具體的Person類 這裡面是指GG類:
package com.diermeng.designPattern.Decorator; /* * 具體的Person */ public class GG implements Person { public void noDecorator() { System.out.println("我是沒有經過打扮的GG"); } public void show() { this.noDecorator(); } } |
藍色牛仔褲裝飾類:
package com.diermeng.designPattern.Decorator.impl; import com.diermeng.designPattern.Decorator.Person; import com.diermeng.designPattern.Decorator.PersonDecorator; /* * 使用藍色牛仔褲裝飾 */ public class JeansDecorator extends PersonDecorator { public JeansDecorator(Person person) { super(person); } public void show() { this.getPerson().show(); this.jeansDecorator(); } public void jeansDecorator() { System.out.println("我是穿上了藍色牛仔褲的GG,帥多了O(∩_∩)O哈哈~"); } public void noDecorator() { } } |
白色長衫裝飾類:
package com.diermeng.designPattern.Decorator.impl; import com.diermeng.designPattern.Decorator.Person; import com.diermeng.designPattern.Decorator.PersonDecorator; /* * 採用白色襯衫的裝飾 */ public class ShirtDecorator extends PersonDecorator{ public ShirtDecorator(Person person) { super(person); } public void show() { this.getPerson().show(); this.shirtDecorator(); } public void shirtDecorator() { System.out.println("我是穿上了白色襯衫的GG,很靚O(∩_∩)O哈哈~"); } public void noDecorator() { } } |
最後我們建立測試用戶端:
package com.diermeng.designPattern.Decorator.client; import com.diermeng.designPattern.Decorator.GG; import com.diermeng.designPattern.Decorator.Person; import com.diermeng.designPattern.Decorator.impl.JeansDecorator; import com.diermeng.designPattern.Decorator.impl.ShirtDecorator; /* * 裝飾模式測試用戶端 */ public class DecoratorTest { public static void main(String[] args) { Person person = new GG(); person.show(); System.out.println("-------------------------------------"); Person swimcar = new JeansDecorator(person); swimcar.show(); System.out.println("-------------------------------------"); Person flySwimCar = new ShirtDecorator(swimcar); flySwimCar.show(); } } |
輸出的結果如下:
我是沒有經過打扮的GG ------------------------------------- 我是沒有經過打扮的GG 我是穿上了藍色牛仔褲的GG,帥多了O(∩_∩)O哈哈~ ------------------------------------- 我是沒有經過打扮的GG 我是穿上了藍色牛仔褲的GG,帥多了O(∩_∩)O哈哈~ 我是穿上了白色襯衫的GG,很靚O(∩_∩)O哈哈~ |
裝飾模式的優缺點分析:
優點:
首先:使用裝飾模式,能夠比使用繼承關係更靈活的擴充項物件的功能,可以按照業務需求隨意的增加對象的功能;其次:通過不同具體的裝飾類以及這些具體的裝飾類排列組合,可以構造出很多不同種類的裝飾結果
缺點:
首先,因為裝飾模式有很多裝飾類,這就會使系統會是系統可以產生很對對象,產生相應的管理問題;其次,真是由於裝飾模式的靈活性,使得隨意組合可能會產生很多能夠正常編譯和啟動並執行對象,但是卻不符合邏輯;最後,由於比較的靈活,想對於繼承而言就比較的容易出錯,而且出錯後也不容排查出錯誤。
裝飾模式的實際應用簡介:
裝飾模式使用一下場合:
想透明並且動態地給對象增加新的職責的時候。
給對象增加的職責,在未來存在增加或減少可能。
用繼承擴充功能不太現實的情況下,應該考慮用組合的方式。
在Java IO庫的設計和實現中就很好的使用了裝飾模式。JDK提供的java.io包中使用了Decorator模式來實現對各種輸入輸出資料流的封裝。以下將以java.io.OutputStream及其子類為例,討論一下Decorator模式在IO中的使用。
我們來看一段用來建立IO流的代碼:
以下是程式碼片段:
try {
OutputStream out = new
DataOutputStream(new FileOutputStream("test.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
這段代碼對於使用過JAVA輸入輸出資料流的人來說再熟悉不過了,我們使用DataOutputStream封裝了一個FileOutputStream。這是一個典型的Decorator模式的使用,FileOutputStream相當於Component,DataOutputStream就是一個Decorator。
在java.io包中,不僅OutputStream用到了Decorator設計模式,InputStream,Reader,Writer等都用到了此模式。而作為一個靈活的,可擴充的類庫,JDK中使用了大量的設計模式,比如在Swing包中的MVC模式,RMI中的Proxy模式等等。對於JDK中模式的研究不僅能加深對於模式的理解,而且還有利於更透徹的瞭解類庫的結構和組成。
溫馨提示:
使用裝飾模式的關鍵是要根據實際的業務需求,針對不同的業務需求進行不同的組合,如果脫離實際的業務需要,就極有可能產生能夠編譯運行通過但卻不符合實際邏輯的情況。
其實,對GG而言,具體穿什麼是不太重要的,更重要的是GG的人品、素質等,還有一點就是個性問題。總之,表現出真我風采即可。