.Net結(jié)構(gòu)型設(shè)計(jì)模式之裝飾模式(Decorator)
一、動(dòng)機(jī)(Motivate)
在房子裝修的過(guò)程中,各種功能可以相互組合,來(lái)增加房子的功用。類似的,如果我們?cè)谲浖到y(tǒng)中,要給某個(gè)類型或者對(duì)象增加功能,如果使用“繼承”的方案來(lái)寫(xiě)代碼,就會(huì)出現(xiàn)子類暴漲的情況。比如:IMarbleStyle是大理石風(fēng)格的一個(gè)功能,IKeepWarm是保溫的一個(gè)接口定義,IHouseSecurity是房子安全的一個(gè)接口,就三個(gè)接口來(lái)說(shuō),House是我們房子,我們的房子要什么功能就實(shí)現(xiàn)什么接口,如果房子要的是復(fù)合功能,接口不同的組合就有不同的結(jié)果,這樣就導(dǎo)致我們子類膨脹嚴(yán)重,如果需要在增加功能,子類會(huì)成指數(shù)增長(zhǎng)。這個(gè)問(wèn)題的根源在于我們“過(guò)度地使用了繼承來(lái)擴(kuò)展對(duì)象的功能”,由于繼承為類型引入的靜態(tài)特質(zhì)(所謂靜態(tài)特質(zhì),就是說(shuō)如果想要某種功能,我們必須在編譯的時(shí)候就要定義這個(gè)類,這也是強(qiáng)類型語(yǔ)言的特點(diǎn)。靜態(tài),就是指在編譯的時(shí)候要確定的東西;動(dòng)態(tài),是指運(yùn)行時(shí)確定的東西),使得這種擴(kuò)展方式缺乏靈活性;并且隨著子類的增多(擴(kuò)展功能的增多),各種子類的組合(擴(kuò)展功能的組合)會(huì)導(dǎo)致更多子類的膨脹(多繼承)。如何使“對(duì)象功能的擴(kuò)展”能夠根據(jù)需要來(lái)動(dòng)態(tài)(即運(yùn)行時(shí))地實(shí)現(xiàn)?同時(shí)避免“擴(kuò)展功能的增多”帶來(lái)的子類膨脹問(wèn)題?從而使得任何“功能擴(kuò)展變化”所導(dǎo)致的影響降為最低?
二、意圖(Intent)
動(dòng)態(tài)地給一個(gè)對(duì)象增加一些額外的職責(zé)。就增加功能而言,Decorator模式比生成子類更為靈活。 —— 《設(shè)計(jì)模式》GoF
三、結(jié)構(gòu)圖(Structure)
四、模式的組成
在裝飾模式中的各個(gè)角色有:
(1)、抽象構(gòu)件角色(Component):給出一個(gè)抽象接口,以規(guī)范準(zhǔn)備接收附加責(zé)任的對(duì)象。
(2)、具體構(gòu)件角色(Concrete Component):定義一個(gè)將要接收附加責(zé)任的類。
(3)、裝飾角色(Decorator):持有一個(gè)構(gòu)件(Component)對(duì)象的實(shí)例,并實(shí)現(xiàn)一個(gè)與抽象構(gòu)件接口一致的接口。
(4)、具體裝飾角色(Concrete Decorator):負(fù)責(zé)給構(gòu)件對(duì)象添加上附加的責(zé)任。
五 、裝飾模式的具體代碼實(shí)現(xiàn)
繼續(xù)拿蓋房子來(lái)說(shuō)事吧。
/// <summary> /// 該抽象類就是房子抽象接口的定義,該類型就相當(dāng)于是Component類型,是餃子餡,需要裝飾的,需要包裝的 /// </summary> public abstract class House { public abstract void Renovation();//房子的裝修方法--該操作相當(dāng)于Component類型的Operation方法 } /// <summary> /// 該抽象類就是裝飾接口的定義,該類型就相當(dāng)于是Decorator類型,如果需要具體的功能,可以子類化該類型 /// </summary> public abstract class DecorationStrategy : House //關(guān)鍵點(diǎn)之二,體現(xiàn)關(guān)系為Is-a,有這這個(gè)關(guān)系,裝飾的類也可以繼續(xù)裝飾了 { //通過(guò)組合方式引用Decorator類型,該類型實(shí)施具體功能的增加這是關(guān)鍵點(diǎn)之一,包含關(guān)系,體現(xiàn)為Has-a protected House _house; protected DecorationStrategy(House house)//通過(guò)構(gòu)造器注入,初始化平臺(tái)實(shí)現(xiàn) { this._house = house; } public override void Renovation() //該方法就相當(dāng)于Decorator類型的Operation方法 { if (this._house != null) { this._house.Renovation(); } } } /// <summary> /// PatrickLiu的房子,我要按我的要求做房子,相當(dāng)于ConcreteComponent類型,這就是我們具體的餃子餡,我個(gè)人比較喜歡韭菜餡 /// </summary> public sealed class MyHouse : House { public override void Renovation() { Console.WriteLine("裝修PatrickLiu的房子"); } } /// <summary> /// 具有安全功能的設(shè)備,可以提供監(jiān)視和報(bào)警功能,相當(dāng)于ConcreteDecoratorA類型 /// </summary> public sealed class HouseSecurityDecorator : DecorationStrategy { public HouseSecurityDecorator(House house) : base(house) { } public override void Renovation() { base.Renovation(); Console.WriteLine("增加安全系統(tǒng)"); } } /// <summary> /// 具有保溫接口的材料,提供保溫功能,相當(dāng)于ConcreteDecoratorB類型 /// </summary> public sealed class KeepWarmDecorator : DecorationStrategy { public KeepWarmDecorator(House house) : base(house) { } public override void Renovation() { base.Renovation(); Console.WriteLine("增加保溫的功能"); } } public class Program { static void Main() { House myselfHouse = new MyHouse();//這就是我們的餃子餡,需要裝飾的房子 DecorationStrategy securityHouse = new HouseSecurityDecorator(myselfHouse); securityHouse.Renovation(); //房子就有了安全系統(tǒng)了 //如果我既要安全系統(tǒng)又要保暖呢,繼續(xù)裝飾就行 DecorationStrategy securityAndWarmHouse = new HouseSecurityDecorator(securityHouse); securityAndWarmHouse.Renovation(); } }
六、裝飾模式的實(shí)現(xiàn)要點(diǎn):
- 通過(guò)采用組合、而非繼承的手法,Decorator模式實(shí)現(xiàn)了在運(yùn)行時(shí)動(dòng)態(tài)地?cái)U(kuò)展對(duì)象功能的能力,而且可以根據(jù)需要擴(kuò)展多個(gè)功能。避免了單獨(dú)使用繼承帶來(lái)的“靈活性差”和“多子類衍生問(wèn)題”。
- Component類在Decorator模式中充當(dāng)抽象接口的角色,不應(yīng)該去實(shí)現(xiàn)具體的行為。而且Decorator類對(duì)于Component類應(yīng)該透明——換言之Component類無(wú)需知道Decorator類,Decorator類是從外部來(lái)擴(kuò)展Component類的功能。
- Decorator類在接口上表現(xiàn)為is-a Component的繼承關(guān)系,即Decorator類繼承了Component類所具有的接口。但在實(shí)現(xiàn)上又表現(xiàn)為has-a Component的組合關(guān)系,即Decorator類又使用了另外一個(gè)Component類。我們可以使用一個(gè)或者多個(gè)Decorator對(duì)象來(lái)“裝飾”一個(gè)Component對(duì)象,且裝飾后的對(duì)象仍然是一個(gè)Component對(duì)象。
- Decorator模式并非解決“多子類衍生的多繼承”問(wèn)題,Decorator模式應(yīng)用的要點(diǎn)在于解決“主體類在多個(gè)方向上的擴(kuò)展功能”——是為“裝飾”的含義。
1、裝飾模式的優(yōu)點(diǎn):
- 把抽象接口與其實(shí)現(xiàn)解耦。
- 抽象和實(shí)現(xiàn)可以獨(dú)立擴(kuò)展,不會(huì)影響到對(duì)方。
- 實(shí)現(xiàn)細(xì)節(jié)對(duì)客戶透明,對(duì)用于隱藏了具體實(shí)現(xiàn)細(xì)節(jié)。
2、裝飾模式的缺點(diǎn):
- 增加了系統(tǒng)的復(fù)雜度
3、在以下情況下應(yīng)當(dāng)使用橋接模式:
- 如果一個(gè)系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間添加更多的靈活性,避免在兩個(gè)層次之間建立靜態(tài)的聯(lián)系。
- 設(shè)計(jì)要求實(shí)現(xiàn)化角色的任何改變不應(yīng)當(dāng)影響客戶端,或者實(shí)現(xiàn)化角色的改變對(duì)客戶端是完全透明的。
- 需要跨越多個(gè)平臺(tái)的圖形和窗口系統(tǒng)上。
- 一個(gè)類存在兩個(gè)獨(dú)立變化的維度,且兩個(gè)維度都需要進(jìn)行擴(kuò)展。
七、.NET 中裝飾模式的實(shí)現(xiàn)
在Net框架中,有一個(gè)類型很明顯的使用了“裝飾模式”,這個(gè)類型就是Stream。Stream類型是一個(gè)抽象接口,它在System.IO命名空間里面,它其實(shí)就是Component。FileStream、NetworkStream、MemoryStream都是實(shí)體類ConcreteComponent。右邊的BufferedStream、CryptoStream是裝飾對(duì)象,它們都是繼承了Stream接口的。
如圖:
Stream就相當(dāng)于Component,定義裝飾的對(duì)象,F(xiàn)ileStream就是要裝飾的對(duì)象,BufferedStream是裝飾對(duì)象。我們看看BufferedStream的定義,部分定義了。
public sealed class BufferedStream : Stream { private const int _DefaultBufferSize = 4096; private Stream _stream; }
到此這篇關(guān)于.Net結(jié)構(gòu)型設(shè)計(jì)模式之裝飾模式(Decorator)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一步步打造漂亮的新聞列表(無(wú)刷新分頁(yè)、內(nèi)容預(yù)覽)第一步
新聞列表是信息管理系統(tǒng)中最常見(jiàn)的,也是最簡(jiǎn)單的,一些簡(jiǎn)單的新聞列表就是一個(gè)table,然后里面循環(huán)寫(xiě)入數(shù)據(jù)2010-07-07ASP.NET?Core中的Configuration配置一
這篇文章介紹了ASP.NET?Core中的Configuration配置,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04.Net?Core中使用MongoDB搭建集群與項(xiàng)目實(shí)戰(zhàn)
本文詳細(xì)講解了.Net?Core中使用MongoDB搭建集群與項(xiàng)目實(shí)戰(zhàn),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02asp.net網(wǎng)絡(luò)數(shù)據(jù)庫(kù)開(kāi)發(fā)實(shí)例精解 源文件
asp.net網(wǎng)絡(luò)數(shù)據(jù)庫(kù)開(kāi)發(fā)實(shí)例精解 源文件...2006-09-09.Net行為型設(shè)計(jì)模式之狀態(tài)模式(State)
這篇文章介紹了.Net行為型設(shè)計(jì)模式之狀態(tài)模式(State),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05.Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter)
這篇文章介紹了.Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05ASP.Net?Core?MVC基礎(chǔ)系列之環(huán)境設(shè)置
這篇文章介紹了ASP.Net?Core?MVC環(huán)境設(shè)置的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02