設計原則
類應該對擴展開放,對修改關閉。spa
做用
動態地給一個對象添加一些額外的職責。就增長功能而言,裝飾者模式相比生成子類更爲靈活,由於生成子類,類的行爲只能在編譯時靜態決定。換句話說,行爲不是來自父類就是子類覆蓋或者添加後的版本。反之,利用裝飾者模式能夠把裝飾者嵌套使用,能夠在運行時實現新的裝飾者增長新的行爲。若是依賴繼承,每當咱們須要新行爲時還須要修改現有的代碼,由於使用繼承,類的行爲只能在編譯時靜態決定。設計
實現要求
- 接口的一致性。由於裝飾者必須必須能取代被裝飾者,因此裝飾者與被裝飾者必須是同一類型,也就是說兩者有共同的父類或者實現了共同的接口。 "類型匹配"能夠經過抽象類(或者普通基類如IO的實現)、接口來實現。
- 利用組合和委託將被裝飾者(組件)添加到裝飾者當中。
- 省略沒必要要時的抽象的Decorator類。當你僅須要添加一個職責時,沒有必要定義抽象Decorator類,你嚐嚐須要處理現存的類層次結構而不是設計一個新系統,這 時你能夠把Decorator向Component轉發請求的職責合併到ConcreteDecorator中。
- 保持接口/父類的簡單性。組件和裝飾必須有一個公共的Component父類。所以保持這個類的簡單性是很重要的;即,它應集中於定義接口而不是存儲數據。對數據表示的定義應延遲到子類中,不然Component類會變得過於複雜和龐大,於是難以大量使用。賦予賦予Component太多的功能也使得,具體的子類有一些它們並不須要的功能的可能性大大增長
裝飾者模式與策略模式
改變對象外殼與改變對象內核。代理
- 咱們能夠將Decorator看做一個對象的外殼,它能夠改變這個對象的行爲。
- 另一種方法是改變對象的內核。例如,Strategy模式就是一個用於改變內核的很好的模式。Component類本來就很龐大時,使用Decorator模式代價過高,Strategy模式相對更好一些。Strategy模式中,組件將它的一些行爲轉發給一個獨立的策略對象,咱們能夠替換strategy對象,從而改變或擴充組件的功能。例如咱們能夠將組件繪製邊界的功能延遲到一個獨立的Border對象中,這樣就能夠支持不一樣的邊界風格。這個Border對象是一個Strategy對象,它封裝了邊界繪製策略。咱們能夠將策略的數目從一個擴充爲任意多個,這樣產生的效果與對裝飾進行遞歸嵌套是同樣的。
裝飾者模式的缺點
- 可能會形成大量的小類
- 客戶代碼中可能依賴某種特定類型(好比某個實現了"接口"的具體類中的非接口方法),若是導入的是裝飾者又不作考慮,可能會出現問題。即:Decorator與它的Component不同,Decorator是一個透明的包裝。若是咱們從對象標識的觀點出發,一個被裝飾了的組件與這個組件是有差異的,所以,使用裝飾時不該該依賴對象標識,而是應該依賴接口標識。
裝飾者模式與代理模式的區別
相同點
這兩種模式都描述了怎樣爲對象提供必定程度上的間接引用,proxy和decorator對象的實現部分都保留了指向另外一個對象的引用,它們向這個對象發送請求。像Decorator模式同樣,Proxy模式構成一個對象併爲用戶提供一致的接口。對象
不一樣點
但與Decorator模式不一樣的是,Proxy模式不能動態地添加或分離性質,它也不是爲遞歸組合而設計的。它的目的是,當直接訪問一個實體不方便或不符合須要時,爲這個實體提供一個替代者,例如,實體在遠程設備上,訪問受到限制或者實體是持久存儲的。繼承
在Proxy模式中,實體定義了關鍵功能,而Proxy提供(或拒絕)對它的訪問。在Decorator模式中,組件僅提供了部分功能,而一個或多個Decorator負責完成其餘功能。Decorator模式適用於編譯時不能(至少不方便)肯定對象的所有功能的狀況。這種開放性使遞歸組合成爲Decorator模式中一個必不可少的部分。而在Proxy模式中則不是這樣,由於Proxy模式強調一種關係(Proxy與它的實體之間的關係),這種關係能夠靜態的表達。模式間的這些差別很是重要,由於它們針對了面向對象設計過程當中一些特定的常常發生問題的解決方法。遞歸
結合使用
但這並不意味着這些模式不能結合使用。能夠設想有一個proxy-decorator,它能夠給proxy添加功能,或是一個decorator-proxy用來修飾一個遠程對象。儘管這種混合可能有用(咱們手邊尚未現成的例子),但它們能夠分割成一些有用的模式。接口
在我看來Java中的動態代理更像是一個proxy-decorator,也就是代理模式與裝飾者模式結合使用。而Java中的靜態代理纔是咱們上面說的那種代理。圖片
適用性
如下狀況使用Decorator模式it
- 在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責。
- 處理那些能夠撤消的職責。
- 當不能採用生成子類的方法進行擴充時。一種狀況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類,好比final修飾的類或者方法。