每當我們買了新房子之後,相信絕大部分人都會進行裝修,給房子增加一些其他新的物品。不過,無論如何裝修,這個房子還是這個房子,最本質的東西並沒有變,有的只是我們通過裝修的方式,給這個房子增加了一些額外的功能…..
通過裝修的方式,給房子增加一些我們想要的額外功能,這種方式,就類似於我們今天要講的設計模式:裝飾者模式。
1.裝飾模式概念
裝飾模式可以在不改變一個物件本身功能的基礎上給物件增加額外的新行為。例如上面的房子裝修,我們買了手機之後給手機裝上手機殼,貼上手機膜等。這些,都可以說是裝修模式的應用。
不過這裡需要注意的是,裝修模式與繼承不一樣,繼承是需要一個子類來擴充物件的功能,而裝飾模式則不一樣,它是通過定義一個裝飾類,在這個裝飾類中持有某些物件的引用,然後通過使用物件之間的關聯關係來取代類之間的繼承關係。
2.定義
裝飾模式(Decorator Pattern):在不必改變原類檔案和原類使用的繼承的情況下,動態地擴充套件一個物件的功能。就增加物件功能來說,裝飾模式比生成子類實現更為靈活。裝飾模式是一種物件結構型模式。
角色
和觀察者模式類似,觀察者模式一般會有如下四個角色:
- 抽象構件(Component).
- 具體構件(ConcreteComponet)。
- 抽象裝飾類(Decorator)。
- 具體裝飾類(ConcreteDecorator)。
下面介紹下四個角色的一些功能、任務。
- 抽象構件:它是具體構件和抽象裝飾類的共同父類,宣告瞭要在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理未被裝飾的物件以及裝飾之後的物件。抽象構件一般定義為介面。
- 具體構件:它是抽象構件類的子類,用於定義具體的構件物件,實現了在抽象構件中宣告的方法,裝飾物件可以給它增加額外的職責(方法)。
- 抽象裝飾類:它也是抽象構件類的子類,用於給具體構件增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件物件的引用,通過該引用可以呼叫裝飾之前構件物件的方法,並通過其子類擴充套件該方法,以達到裝飾的目的。
- 具體裝飾類:它是抽象裝飾類的子類,負責向構件新增新的職責。每一個具體裝飾類都定義了一些新的行為,它可以呼叫在抽象裝飾類中定義的方法,並可以增加新的方法用以擴充物件的行為。
下面我給個例子吧,看個例子就比較知道這些角色都是個什麼情況了。
3.例子
在n年前,人類捕捉了動物之後,會直接殺了之後就拿來吃,而不會把它烤熟、弄上一些配料之後再吃。但是到了後來,人類就懂得了把動物烤熟、弄上配料之後再吃了。
現在我們假設人類本來是不會烤熟之後再吃的,而是被裝飾了一些額外的能力之後,才知道烤熟之後再吃。(貌似這個例子有點勉強…..)。
現在開始定義上面那四個角色:
1.抽象構件
/**
* 定義作為人類應有的一些規範
*/
public interface Human {
void eating();
}
2.具體構件
/**
* 具體構件類
*/
public class Man implements Human{
@Override
public void eating() {
System.out.println("吃剛剛捕獲的美味佳餚");
}
}
3.抽象裝飾類
/**
* 抽象裝飾者,需要實現抽象構件介面
*/
public class Decorator implements Human{
//維持對抽象構件的引用
private Human human;
//注入構件例項
public Decorator(Human human) {
this.human = human;
}
@Override
public void eating() {
human.eating();
}
}
注意: 在Decorator中並未真正實現eat()方法,而只是呼叫原有Human物件的eating()方法,它沒有真正實施裝飾,而是提供一個統一的介面,將具體裝飾過程交給子類完成。
4.具體裝飾類
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Human human){
super(human);
}
@Override
public void eating() {
System.out.println("把捕捉的動物給烤熟了,在加些配料");
super.eating();
System.out.println("吃完飯之後洗手");
}
//需要增加的其他方法
}
5.測試類
public class Demo {
public static void main(String[] args){
Human man = new Man();
//沒進行裝飾之前
man.eating();
System.out.println("--------------------");
//進行裝飾之後
man = new ConcreteDecorator(man);
man.eating();
}
}
6.列印結果
吃剛剛捕獲的美味佳餚
--------------------
把捕捉的動物給烤熟了,在加些配料
吃剛剛捕獲的美味佳餚
吃完飯之後洗手
從這個簡單的例子可以看到,沒有並沒有改變原來的Man類,同時也沒有定義他的子類來進行功能的擴充,而是通過一個裝飾類的輔助來實現Man類功能的增強,這就是裝飾者模式的作用。
優缺點
優點:
1,使用裝飾者模式比使用繼承更加靈活,因為它選擇通過一種動態的方式來擴充套件一個物件的功能,在執行時可以選擇不同的裝飾器,從而實現不同的行為。
2,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合。可以使用多個具體裝飾類來裝飾同一物件,得到功能更為強大的物件。
3,具體構件類與具體裝飾類可以獨立變化,他能是低耦合的。使用者可以根據需要來增加新的具體構件類和具體裝飾類,在使用時再對其進行各種組合,原有程式碼無須改變,符合“開閉原則”。
缺點:
1,會產生很多的小物件,增加了系統的複雜性
2,由於使用裝飾模式,可以比使用繼承關係需要較少數目的類。使用較少的類,當然使設計比較易於進行。但是,在另一方面,使用裝飾模式會產生比使用繼承關係更多的物件。更多的物件會使得查錯變得困難,特別是這些物件看上去都很相像。
參考資料:
- 設計模式java版。
- Head First設計模式
完
關注公我的眾號:苦逼的碼農,獲取更多原創文章,後臺回覆禮包送你一份時下熱門的資源大禮包。同時也感謝把文章介紹給更多需要的人
啊啊