裝飾器模式主要對現有的類對象進行包裹和封裝,以期望在不改變類對象及其類定義的情況下,為對象添加額外功能。是一種對象結構型模式。需要注意的是,該過程是通過調用被包裹之後的對象完成功能添加的,而不是直接修改現有對象的行為,相當于增加了中間層。類似于python中的@裝飾器。
下面還是按照老規矩,先來了解一下該模式相關的概念和原理,然後通過兩個具體的執行個體體會一下如何在實際開發中應用該模式。
可以動态的為同一類的不同對象加以修飾以添加新的功能。
靈活的對類對象功能進行擴充。
優點:
相比較于類的繼承來擴充功能,對對象進行包裹更加的靈活;
裝飾類和被裝飾類互相獨立,耦合度較低;
缺點:
沒有繼承結構清晰;
包裹層數較多時,難以了解和管理;
動态的增加對象的功能;
不能以派生子類的方式來擴充功能;
限制對象的執行條件;
參數控制和檢查等;
下面是GoF介紹的典型的裝飾器模式的UML類圖:
Component:
對象的接口類,定義裝飾對象和被裝飾對象的共同接口;
ConcreteComponent:
被裝飾對象的類定義;
Decorator:
裝飾對象的抽象類,持有一個具體的被修飾對象,并實作接口類繼承的公共接口;
ConcreteDecorator:
具體的裝飾器,負責往被裝飾對象添加額外的功能;
說明:
由于這個模式從實際的例子來了解更加的直覺友善,是以這裡不再單獨的實作上面的UML結構代碼。
先來通過一個簡單的畫圖的執行個體來直覺感受一下。
前提:
系統中存在一個畫圓的類,該類隻是用來畫圓,以及其他一些大小和位置等參數的控制。
新加需求:
可以對圓的邊進行着色
可以對圓填充顔色;
可以同時對邊和内部着色;
這個需求的正常方法實作可能如下:
對畫圓類進行疊代,以支援邊和内部顔色填充 ;
畫圓類作為父類,分别定義三個子類,繼承父類的畫圓方法,子類分别實作對應的作色需求;
上面的兩個方法都是可行的,也是比較直覺的,這裡我們嘗試使用裝飾器模式來實作,作為以上兩種方法的對比。
下面來看一下裝飾器模式實作該需求的UML類圖:
接口類:shape
畫圓類:Circle
抽象裝飾器類:Decorator
為圓邊着色裝飾器類:CircleEdge
為圓填充顔色裝飾器類:CircleEdge
示範:
結果:
上面我們通過實作兩個裝飾器分别完成對邊着色和填充的需求,通過對裝飾器的進一步裝飾,我們完成了同時着色的需求。
接下來我們在使用網絡資料傳輸的例子來體會一下裝飾器模式,下圖表示的是應用層的檔案傳輸協定FTP通過TCP來傳輸資料:
雖然應用層可以越過傳輸層直接使用網絡層進行資料發送(如,ICMP),但多數都會使用傳輸層的TCP或者UDP進行資料傳輸的。
下面我們用裝飾器模式來表示一下應用層資料通過傳輸層來發送資料,UML類圖如下:
上述圖中表示了,應用層的資料通過添加TCP頭或者UDP頭,然後通過下面的網絡層send資料。
資料報接口類:Datagram
應用層資料類:AppDatagram
傳輸層類(抽象裝飾器):TransportLayer
添加TCP頭部類:UseTCP
添加TCP頭部類:UseUDP
當然這裡例子中已經添加過TCP頭部的資料報不能再使用UDP傳輸了,無意義,也被必要。
其實所謂裝飾器,本質上是對現有類對象的包裹,得到一個加強版的對象。
和python中@裝飾器不同的是:
python中的裝飾器是作用于函數或者類定義的,并直接覆寫掉了原來函數或者類的定義;
裝飾器模式僅僅是修改了了已經産生的對象的行為,和類定義沒有半點關系;
通過上面的兩個例子,應該對裝飾器模式有了一個簡單的認識。
另外,要體會到什麼時候用繼承什麼時候用裝飾器。