動態(tài)地給一個對象增加一些額外的職責(zé)综膀,就增加對象功能來說挪挤,裝飾模式比生成子類實現(xiàn)更為靈活洞拨。
類型
結(jié)構(gòu)型
簡介
裝飾模式是一種用于替代繼承的技術(shù),它通過一種無須定義子類的方式來給對象動態(tài)增加職責(zé)讼积,使用對象之間的關(guān)聯(lián)關(guān)系取代類之間的繼承關(guān)系哨苛。
參與者
在裝飾模式中,為了讓系統(tǒng)具有更好的靈活性和可擴展性币砂,我們通常會定義一個抽象裝飾類建峭,而將具體的裝飾類作為它的子類。
- Component(抽象構(gòu)件):它是具體構(gòu)件和抽象裝飾類的共同父類决摧,聲明了在具體構(gòu)件中實現(xiàn)的業(yè)務(wù)方法亿蒸,它的引入可以使客戶端以一致的方式處理未被裝飾的對象以及裝飾之后的對象,實現(xiàn)客戶端的透明操作掌桩。
- ConcreteComponent(具體構(gòu)件):它是抽象構(gòu)件類的子類边锁,用于定義具體的構(gòu)件對象,實現(xiàn)了在抽象構(gòu)件中聲明的方法波岛,裝飾器可以給它增加額外的職責(zé)(方法)茅坛。
- Decorator(抽象裝飾類):它也是抽象構(gòu)件類的子類,用于給具體構(gòu)件增加職責(zé)则拷,但是具體職責(zé)在其子類中實現(xiàn)贡蓖。它維護(hù)一個指向抽象構(gòu)件對象的引用,通過該引用可以調(diào)用裝飾之前構(gòu)件對象的方法煌茬,并通過其子類擴展該方法斥铺,以達(dá)到裝飾的目的。
- ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類坛善,負(fù)責(zé)向構(gòu)件添加新的職責(zé)晾蜘。每一個具體裝飾類都定義了一些新的行為,它可以調(diào)用在抽象裝飾類中定義的方法眠屎,并可以增加新的方法用以擴充對象的行為剔交。
用法
代碼助記
客戶端并不會覺得對象在裝飾前和裝飾后有什么不同,對客戶端透明改衩。
- 抽象裝飾類和具體構(gòu)件類繼承于同一父類(抽象構(gòu)件)岖常;
- 抽象裝飾類中有一指向抽象構(gòu)件對象的引用,由客戶端使用構(gòu)造器或set注入燎字;
- 抽象裝飾類調(diào)用抽象構(gòu)件對象的原業(yè)務(wù)方法(多態(tài)到具體構(gòu)件類)腥椒;
- 具體裝飾類復(fù)寫業(yè)務(wù)方法阿宅,調(diào)用抽象類業(yè)務(wù)方法,并擴展業(yè)務(wù)方法笼蛛;
- 客戶端需要知道裝飾類洒放,由客戶端組裝(注入構(gòu)件對象);
一次裝飾
將具體構(gòu)件對象注入裝飾類中滨砍。
嵌套(多次)裝飾
將一個已經(jīng)裝飾過的裝飾子類對象再注入裝飾類中往湿。
兩種模式
開發(fā)過程中,具體裝飾類中有可能有新增的方法需要調(diào)用惋戏。這樣客戶端聲明對象時领追,不能統(tǒng)一使用抽象構(gòu)件類型定義,而需要將調(diào)用新增方法的地方使用具體裝飾類來聲明响逢。這種情況稱為非透明绒窑,其實是由多態(tài)中向上轉(zhuǎn)型后不能再調(diào)用子類中新增方法引入的。
透明裝飾模式(Transparent)
- 在透明裝飾模式中舔亭,要求客戶端完全針對抽象編程些膨。
- 要求客戶端程序不應(yīng)該將對象聲明為具體構(gòu)件類型或具體裝飾類型,而應(yīng)該全部聲明為抽象構(gòu)件類型钦铺。
- 使用抽象構(gòu)件類型Component定義全部具體構(gòu)件對象和具體裝飾對象订雾,客戶端可以一致地使用這些對象,無須關(guān)心它們的區(qū)別矛洞。此外洼哎,還可以對一個已裝飾過的對象進(jìn)行多次裝飾,得到更為復(fù)雜沼本、功能更為強大的對象噩峦。
半透明裝飾模式(Semi-transparent)
- 為了能夠調(diào)用到新增方法,我們不得不用具體裝飾類型來定義裝飾之后的對象擅威,而具體構(gòu)件類型還是可以使用抽象構(gòu)件類型來定義壕探;
- 對于客戶端而言,具體構(gòu)件類型無須關(guān)心郊丛,是透明的;但是具體裝飾類型必須指定瞧筛,這是不透明的厉熟;
- 半透明裝飾模式可以給系統(tǒng)帶來更多的靈活性,設(shè)計相對簡單较幌,使用起來也非常方便揍瑟;
- 缺點在于不能實現(xiàn)對同一個對象的多次裝飾,而且客戶端需要有區(qū)別地對待裝飾之前的對象和裝飾之后的對象乍炉。
總結(jié)
- 盡量保持裝飾類的接口與被裝飾類的接口相同绢片,應(yīng)該盡量使用透明裝飾模式滤馍。
- 盡量保持具體構(gòu)件類ConcreteComponent是一個“輕”類,也就是說不要把太多的行為放在具體構(gòu)件類中底循,我們可以通過裝飾類對其進(jìn)行擴展巢株。
- 如果只有一個具體構(gòu)件類,那么抽象裝飾類可以作為該具體構(gòu)件類的直接子類熙涤。
優(yōu)點
- 對于擴展一個對象的功能阁苞,裝飾模式比繼承更加靈活性,不會導(dǎo)致類的個數(shù)急劇增加祠挫。
- 可以通過一種動態(tài)的方式來擴展一個對象的功能那槽,通過配置文件可以在運行時選擇不同的具體裝飾類,從而實現(xiàn)不同的行為等舔。
- 可以對一個對象進(jìn)行多次裝飾骚灸,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創(chuàng)造出很多不同行為的組合慌植,得到功能更為強大的對象逢唤。
- 具體構(gòu)件類與具體裝飾類可以獨立變化,用戶可以根據(jù)需要增加新的具體構(gòu)件類和具體裝飾類涤浇,原有類庫代碼無須改變鳖藕,符合“開閉原則”。
缺點
- 使用裝飾模式進(jìn)行系統(tǒng)設(shè)計時將產(chǎn)生很多小對象只锭,這些對象的區(qū)別在于它們之間相互連接的方式有所不同著恩,而不是它們的類或者屬性值有所不同,大量小對象的產(chǎn)生勢必會占用更多的系統(tǒng)資源蜻展,在一定程序上影響程序的性能喉誊。
- 裝飾模式提供了一種比繼承更加靈活機動的解決方案,但同時也意味著比繼承更加易于出錯纵顾,排錯也很困難伍茄,對于多次裝飾的對象,調(diào)試時尋找錯誤可能需要逐級排查施逾,較為繁瑣敷矫。