設計模式之裝飾模式
裝飾模式(Decorator):
動態地給一個物件新增一些額外的職責,就增加功能來說,裝飾模式比生成子類更加靈活。
(再來一波生硬的概念...) "Component"是定義一個物件介面,可以給這些物件動態地新增職責。ConcreteComponent是定義了一個具體的物件,也可以給這個物件新增一些職責。Decorator,裝飾抽象類,繼承了Component,從外類來擴充套件Component類的功能,但對於Component來說,是無需知道Decorator的存在的。至於ConcreteDecorator就是具體的裝飾物件,起到個Component新增職責的功能。
案例走起
現在公司有很多鋼筆,紙張和書本,膝上型電腦等等...有桌子和書櫃等...這些東西放在哪裡完全由你決定...例如桌子,開始是個空桌子,用什麼來"修飾"呢?我可以放鋼筆也可以放紙張...接下來看看怎麼實現的把!
1.根據上面的uml圖,首先我們來建立傢俱()把,賦予它放置東西的能力(行為)
1 package component; 2 3 /** 4* 傢俱 5* @author DeepSleeping 6* 7*/ 8 public interface Furniture { 9 10/** 11* 放置物品 12*/ 13void place(); 14 }
2.接下來我們建立具體被修飾類(這裡我就建立桌子table把)
1 package component.concreteComponent; 2 3 import component.Furniture; 4 5 /** 6* 具體被裝飾類 7* 桌子 8* @author DeepSleeping 9* 10*/ 11 public class Table implements Furniture{ 12 13@Override 14public void place() { 15System.out.println("桌子..."); 16} 17 18 }
3.然後就是建立抽象修飾類把
1 package decoration; 2 3 import component.Furniture; 4 5 /** 6* 裝飾抽象類 7* @author DeepSleeping 8* 9*/ 10 public class Decorator implements Furniture{ 11 12//持有被裝飾類的引用 13Furniture furniture; 14 15//通過構造方法傳入被裝飾類 16public Decorator(Furniture furniture){ 17 18this.furniture = furniture; 19} 20 21 22@Override 23public void place() { 24//呼叫被裝飾類的方法 25furniture.place(); 26} 27 28 }
4.抽象修飾類下面自然是那些用來修飾具體被修飾類(桌子、書櫃...)的具體修飾類(鋼筆,紙張...)
1 package decoration.concreteDecoration; 2 3 import component.Furniture; 4 import decoration.Decorator; 5 6 /** 7* 具體修飾類(紙張) 8* @author DeepSleeping 9* 10*/ 11 public class Paper extends Decorator{ 12 13/** 14* 因為父類Decorator中寫了有參構造方法,所以無參構造方法就會沒有了 15* 子類繼承父類會預設實現父類的無參構造方法,現在必須得手動實現父類中的有參構造方法... 16* 這樣就把被裝飾類傳進來了... 17* @param furniture 18*/ 19public Paper(Furniture furniture) { 20super(furniture); 21 22} 23 24/** 25* 修飾 26*/ 27@Override 28public void place() { 29super.place(); 30//新增自己對應的修飾內容 31System.out.print("放置了一張紙...\t"); 32} 33 34 35 }
1 package decoration.concreteDecoration; 2 3 import component.Furniture; 4 import decoration.Decorator; 5 6 /** 7* 具體修飾類(鋼筆) 8* @author DeepSleeping 9* 10*/ 11 public class Pen extends Decorator { 12 13Furniture furniture; 14 15public Pen(Furniture furniture) { 16super(furniture); 17} 18 19@Override 20public void place() { 21super.place(); 22System.out.println("放置了一支鋼筆..."); 23} 24 }
5.好了,接下來就是測試了...
1 package test; 2 3 import component.Furniture; 4 import component.concreteComponent.Table; 5 import decoration.concreteDecoration.Paper; 6 import decoration.concreteDecoration.Pen; 7 8 9 public class TestDecorator { 10 11public static void main(String[] args) { 12//例項化被裝飾類的物件 13Furniture table = new Table(); 14 15System.out.println("******************領導A:放一張紙到桌子上...******************"); 16table = new Paper(table); 17table.place(); 18 19System.out.println(); 20//再放一支鋼筆在桌子上 21System.out.println("******************領導B:放一支鋼筆到桌子上...******************"); 22table = new Pen(table); 23table.place(); 24 25System.out.println(); 26System.out.println("******************領導C:放4支鋼筆和一張紙到桌子上...******************"); 27//再放4支鋼筆和一張紙在桌子上 28table = new Pen(new Pen(new Pen(new Pen(new Paper(table))))); 29table.place(); 30} 31 }
6.執行結果...
小結:
從上述程式碼中很明顯可以看的出來,首先是一個空的桌子我們可以用鋼筆或者紙張等來"修飾"這個桌子..
如果需要拓展,可以繼續寫書櫃,然後新增 書,各種修飾,書櫃中想放什麼動態新增就是了,非常的方便,如果有新的東西比如運來了一批海鮮,添加個海鮮類就好了,至於想放在書櫃上還是書桌上由你自己來定
不需要去修改之前的程式碼。
一個軟體肯定會有需求的變更拓展,這時候只要增加那些"修飾"就可以了,這裡就是"開閉原則"的良好體現把!
"開放-封閉原則是面向物件設計的核心所在。遵循這個原則可以帶來面向物件技術所聲稱的巨大好處,也就是可維護、可拓展、可複用、靈活性好。開發人員應該僅對程式中呈現出頻繁變化的哪些部分做出抽象,然而,對於應用程式中的每個部分都刻意地進行抽象同樣不是一個好主意。拒絕不成熟的抽象和抽象本身一樣重要。"
學習心得:
學習設計模式以及瞭解與設計有關的東西或者看看原始碼,對自己的思想有了一些啟發把,還是挺有作用的,學習應該心平氣和腳踏實地。
不過目前呢給我的感覺還是"幹嘛這麼麻煩...就那樣放一起不就好了,有改變的話改下程式碼就好了",不過在學習中,發現,到處都在強調"開閉"等,拓展性啥的。。
基礎!基礎!基礎!基礎真的很重要! 之前看代理模式完全看不懂,去補了一下多型,這裡我覺得又是很好的利用了多型來進行"通訊"
多型,反射,註解,各種,還有多執行緒啊好多好多需要去學習和鞏固深入的,漫漫長路共勉吧!
裝飾模式在JAVA中的IO流就是很好的例子...):
具體的例子以及前輩運用裝飾模式自定義IO流的demo在下面的參考部落格中有體現...
本文參考
部落格:https://blog.csdn.net/android_zyf/article/details/68343953
書籍:《大話設計模式》