天天看點

C#設計模式(9)——裝飾者模式(Decorator Pattern)

在軟體開發中,我們經常想要對一類對象添加不同的功能,例如要給手機添加貼膜,手機挂件,手機外殼等,如果此時利用繼承來實作的話,就需要定義無數的類,如StickerPhone(貼膜是手機類)、AccessoriesPhone(挂件手機類)等,這樣就會導緻 ”子類爆炸“問題,為了解決這個問題,我們可以使用裝飾者模式來動态地給一個對象添加額外的職責。下面讓我們看看裝飾者模式。

裝飾者模式以對客戶透明的方式動态地給一個對象附加上更多的責任,裝飾者模式相比生成子類可以更靈活地增加功能。

這裡以手機和手機配件的例子來示範裝飾者模式的實作,具體代碼如下:

此時用戶端調用代碼如下:

從上面的用戶端代碼可以看出,用戶端可以動态地将手機配件增加到手機上,如果需要添加手機外殼時,此時隻需要添加一個繼承Decorator的手機外殼類,進而,裝飾者模式擴充性也非常好。

實作完了裝飾者模式之後,讓我們看看裝飾者模式實作中類之間的關系,具體見下圖:

C#設計模式(9)——裝飾者模式(Decorator Pattern)

在裝飾者模式中各個角色有:

抽象構件(Phone)角色:給出一個抽象接口,以規範準備接受附加責任的對象。

具體構件(AppPhone)角色:定義一個将要接收附加責任的類。

裝飾(Dicorator)角色:持有一個構件(Component)對象的執行個體,并定義一個與抽象構件接口一緻的接口。

具體裝飾(Sticker和Accessories)角色:負責給構件對象 ”貼上“附加的責任。

看完裝飾者模式的詳細介紹之後,我們繼續分析下它的優缺點。

裝飾這模式和繼承的目的都是擴充對象的功能,但裝飾者模式比繼承更靈活

通過使用不同的具體裝飾類以及這些類的排列組合,設計師可以創造出很多不同行為的組合

裝飾者模式有很好地可擴充性

缺點:裝飾者模式會導緻設計中出現許多小對象,如果過度使用,會讓程式變的更複雜。并且更多的對象會是的差錯變得困難,特别是這些對象看上去都很像。

下面讓我們看看裝飾者模式具體在哪些情況下使用,在以下情況下應當使用裝飾者模式:

需要擴充一個類的功能或給一個類增加附加責任。

需要動态地給一個對象增加功能,這些功能可以再動态地撤銷。

需要增加由一些基本功能的排列組合而産生的非常大量的功能

在.NET 類庫中也有裝飾者模式的實作,該類就是System.IO.Stream,下面看看Stream類結構:

C#設計模式(9)——裝飾者模式(Decorator Pattern)

上圖中,BufferedStream、CryptoStream和GZipStream其實就是兩個具體裝飾類,這裡的裝飾者模式省略了抽象裝飾角色(Decorator)。下面示範下用戶端如何動态地為MemoryStream動态增加功能的。

到這裡,裝飾者模式的介紹就結束了,裝飾者模式采用對象組合而非繼承的方式實作了再運作時動态地擴充對象功能的能力,而且可以根據需要擴充多個功能,避免了單獨使用繼承帶來的 ”靈活性差“和”多子類衍生問題“。同時它很好地符合面向對象設計原則中 ”優先使用對象組合而非繼承“和”開放-封閉“原則。

繼續閱讀