《设计模式》之装饰器模式
一、什么是裝飾器模式
當(dāng)需要對類的功能進行拓展時,一般可以使用繼承,但如果需要拓展的功能種類很繁多,那勢必會生成很多子類,增加系統(tǒng)的復(fù)雜性,并且使用繼承實現(xiàn)功能拓展時,我們必須能夠預(yù)見這些拓展功能,也就是這些功能在編譯時就需要確定了。那么有什么更好的方式實現(xiàn)功能的拓展嗎?答案就是裝飾器模式。
裝飾器模式可以動態(tài)給對象添加一些額外的職責(zé)從而實現(xiàn)功能的拓展,在運行時選擇不同的裝飾器,從而實現(xiàn)不同的行為;比使用繼承更加靈活,通過對不同的裝飾類進行排列組合,創(chuàng)造出很多不同行為,得到功能更為強大的對象;符合“開閉原則”,被裝飾類與裝飾類獨立變化,用戶可以根據(jù)需要增加新的裝飾類和被裝飾類,在使用時再對其進行組合,原有代碼無須改變。
但是裝飾器模式也存在缺點,首先會產(chǎn)生很多的小對象,增加了系統(tǒng)的復(fù)雜性,第二是排錯比較困難,對于多次裝飾的對象,調(diào)試時尋找錯誤可能需要逐級排查,較為煩瑣。
二、UML結(jié)構(gòu)圖
- Component:抽象構(gòu)件,是定義一個對象接口,可以給這個對象動態(tài)地添加職責(zé)。
- ConcreteComponent:具體構(gòu)件,是定義了一個具體的對象,也可以給這個對象添加一些職責(zé)。
- Decorator:抽象裝飾類,繼承自 Component,從外類來擴展 Component 類的功能,但對于 Component 來說,是無需知道 Decorator 存在的。
- ConcreteDecorator:具體裝飾類,起到給 Component 添加職責(zé)的功能。
裝飾者與被裝飾者都擁有共同的超類,但這里繼承的目的是繼承類型,而不是行為。
三、代碼實現(xiàn)
3.1、代碼示例一
//定義被裝飾者 interface Human {void wearClothes(); }//定時裝飾者 abstract class Decorator implements Human {private Human human;public Decorator(Human human){this.human = human;}@Overridepublic void wearClothes(){human.wearClothes();} }//下面定義三種裝飾,這是第一個,第二個第三個功能依次細(xì)化,即裝飾者的功能越來越多 class Decorator_zero extends Decorator {public Decorator_zero(Human human) {super(human);}public void goHome() {System.out.println("進房子。。");}@Overridepublic void wearClothes() {super.wearClothes();goHome();} }class Decorator_first extends Decorator {public Decorator_first(Human human) {super(human);}public void goClothespress() {System.out.println("去衣柜找找看。。");}@Overridepublic void wearClothes() {super.wearClothes();goClothespress();} }class Decorator_two extends Decorator {public Decorator_two(Human human) {super(human);}public void findClothes() {System.out.println("找到一件D&G。。");}@Overridepublic void wearClothes() {super.wearClothes();findClothes();} }class Person implements Human {@Overridepublic void wearClothes() {System.out.println("穿什么呢。。");} }//測試類 public class DecoratorTest {public static void main(String[] args){Human person = new Person();Decorator decorator = new Decorator_two(new Decorator_first(new Decorator_zero(person)));decorator.wearClothes();} }運行結(jié)果:
其實就是進房子找衣服,通過裝飾者的三層裝飾,把細(xì)節(jié)變得豐富,該Demo的關(guān)鍵點:
(1)Decorator 抽象類持有Human接口,方法全部委托給該接口調(diào)用,目的是交給該接口的實現(xiàn)類進行調(diào)用。
(2)Decorator 抽象類的子類,即具體裝飾者,里面都有一個構(gòu)造方法調(diào)用 super(human),這里就體現(xiàn)了抽象類依賴于子類實現(xiàn),即抽象依賴于實現(xiàn)的原則。因為構(gòu)造函數(shù)的參數(shù)都是 Human 類型,只要是該 Human 的實現(xiàn)類都可以傳遞進去,即表現(xiàn)出 Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human))) 這種結(jié)構(gòu)的樣子,所以當(dāng)調(diào)用 dt.wearClothes() 的時候,又因為每個具體裝飾者類中,都先調(diào)用 super.wearClothes() 方法,而該 super 已經(jīng)由構(gòu)造函數(shù)傳遞并指向了具體的某一個裝飾者類,那么最終調(diào)用的就是裝飾類的方法,然后才調(diào)用自身的裝飾方法,即表現(xiàn)出一種裝飾、鏈?zhǔn)降念愃朴谶^濾的行為。
(3)具體被裝飾者類,可以定義初始的狀態(tài)或者初始的自己的裝飾,后面的裝飾行為都在此基礎(chǔ)上一步一步進行點綴、裝飾。
(4)裝飾者模式的設(shè)計原則為:對擴展開放、對修改關(guān)閉,這句話體現(xiàn)在如果想擴展被裝飾者類的行為,無須修改裝飾者抽象類,只需繼承裝飾者抽象類,實現(xiàn)額外的一些裝飾或者叫行為即可對被裝飾者進行包裝。所以:擴展體現(xiàn)在繼承、修改體現(xiàn)在子類中,而不是具體的抽象類,這充分體現(xiàn)了依賴倒置原則,這是自己理解的裝飾者模式。
3.2、代碼示例二
現(xiàn)在需要一個漢堡,主體是雞腿堡,可以選擇添加生菜、醬、辣椒等等許多其他的配料,這種情況下就可以使用裝飾者模式。
漢堡基類(被裝飾者,相當(dāng)于上面的Human)
public abstract class Humburger { protected String name ; public String getName(){ return name; } public abstract double getPrice(); }雞腿堡類(被裝飾者的初始狀態(tài),有些自己的簡單裝飾,相當(dāng)于上面的Person)?
public class ChickenBurger extends Humburger { public ChickenBurger(){ name = "雞腿堡"; } @Override public double getPrice() { return 10; } }配料的基類(裝飾者,用來對漢堡進行多層裝飾,每層裝飾增加一些配料,相當(dāng)于上面Decorator)
public abstract class Condiment extends Humburger { public abstract String getName(); }生菜(裝飾者的第一層,相當(dāng)于上面的decorator_zero)
public class Lettuce extends Condiment { Humburger humburger; public Lettuce(Humburger humburger){ this.humburger = humburger; } @Override public String getName() { return humburger.getName()+" 加生菜"; } @Override public double getPrice() { return humburger.getPrice()+1.5; } }辣椒(裝飾者的第二層,相當(dāng)于上面的decorator_first)
public class Chilli extends Condiment { Humburger humburger; public Chilli(Humburger humburger){ this.humburger = humburger; } @Override public String getName() { return humburger.getName()+" 加辣椒"; } @Override public double getPrice() { return humburger.getPrice(); //辣椒是免費的哦 } }測試類:
package decorator; public class Test { public static void main(String[] args) { Humburger humburger = new ChickenBurger(); System.out.println(humburger.getName()+" 價錢:"+humburger.getPrice()); Lettuce lettuce = new Lettuce(humburger); System.out.println(lettuce.getName()+" 價錢:"+lettuce.getPrice()); Chilli chilli = new Chilli(humburger); System.out.println(chilli.getName()+" 價錢:"+chilli.getPrice()); Chilli chilli2 = new Chilli(lettuce); System.out.println(chilli2.getName()+" 價錢:"+chilli2.getPrice()); } }輸出:
雞腿堡 ?價錢:10.0 ?
雞腿堡 加生菜 ?價錢:11.5 ?
雞腿堡 加辣椒 ?價錢:10.0 ?
雞腿堡 加生菜 加辣椒 ?價錢:11.5 ?
原文鏈接:?Java設(shè)計模式之結(jié)構(gòu)型:裝飾器模式_張維鵬的博客-CSDN博客?
總結(jié)
以上是生活随笔為你收集整理的《设计模式》之装饰器模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android P新的图片格式 HEIF
- 下一篇: 使用.Net5尝鲜的一些小总结及Conf