Decorator(裝飾)模式(對象結構型模式)
一. 意圖
動态地給一個對象添加一些額外的職責. 就增加功能來說, Decorator模式相比生成子類更為靈活.
二. 适用性
1. 在不影響其他對象的情況下, 以動态, 透明的方式給單個對象添加職責.
2. 處理那些可以撤消的職責.
3. 當不能采用生成子類的方法進行擴充時. 一種情況是, 可能有大量獨立的擴充, 為支援每一種組合将産生大量的子類, 使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隐藏, 或類定義不能用于生成子類.
三. 模式結構
圖1
四. 角色說明
Component
—定義一個對象接口,可以給這些對象動态地添加職責。
ConcreteComponent
—定義一個對象,可以給這個對象添加一些職責。
Decorator
—維持一個指向Component對象的指針, 并定義一個與Component接口一緻的接口.
ConcreteDecorator
—向元件添加職責
Decorator将請求轉發給它的Component對象, 并有可能在轉發請求前後執行一些附加的動作.
五. 說明
對一個已經封裝好的功能增加功能, 因為已經封裝好了, 你不可能在它的内部進行修改. 現在就有兩種方式:
1. 使用繼承, 生成一個該功能的子類. 這個子類的要求肯定是要實作父類的接口(父類公開出來的方法).(因為父類已經在用了).
然後對父類對應的方法進行功能擴充.(在父類的方法裡面你喜歡怎樣就怎樣了).
2. 生成一個類, 該類包含該原功能類的對象. 這個類同樣實作原功能類的接口.(新類中對應的接口調用對象對應的接口).
(新類與功能類繼承與同一接口, 這樣原來的使用者就不需要改動代碼.)(這就是Decorator模式了)
使用Decorator模式時應注意以下幾點:
1. 接口的一緻性 裝飾對象的接口必須與它所裝飾的Component的接口是一緻的, 是以,所有的ConcreteDecorator類必須有一個公共的父類.
2. 沒有抽象的Decorator類, 因為你常常需要處理現存的類層次結構而不是設計一個新系統, Decorator與ConcreteComponent位于同一類層次即可(繼承于同一父類).
3. 保持Component類的簡單性 為了保證接口的一緻性, 元件和裝飾必須有一個公共的Component父類. 是以保持Component類的簡單性是很重要的: 即它應集中于定義接口而不是存儲資料. 對資料表示的定義應延遲到子類中, 否則Component類會變得過于複雜和龐大, 因而難以大量使用。賦予Component太多的功能也使得,具體的子類有一些它們并不需要的功能的可能性大大增加。
4. 改變對象外殼與改變對象核心, 我們可以将Decorator看作一個對象的外殼, 它可以改變這個對象的行為. 另外一種方法是改變對象的核心. 例如Strategy模式就是一個用于改變核心的很好的模式.
六. 我的了解
1. 有一個類, 你不能改變它的内部實作, 但是需要擴充它的功能.你可以使用一個新類, 新類包含一個原類的對象, 在調用對象的方法前後擴充它的功能. 有一個問題, 原類已經再使用了, 它的接口已經被客戶使用了. 我們擴充它的功能的前提是盡量的讓客戶少改代碼, 少改變. 如果原類的功能方法不是繼承接口的(原類沒有父類, 或者說原類提供給客戶的方法不是接口), 那Decorator模式無法使用的. ConcreteComponent與Decorator必須有相同的接口(要擴充功能所對應的那個接口).
圖2
2. Decorator中包含一個ConcreteComponent對象, Decorator::Operation中調用ConcreteComponent::Operation.
而ConcreteDecorator::Operation調用Decorator::Operation (可以看到ConcreteComponent與ConcreteDecorator被Decorator隔開了解耦了).
這樣隔開, 效果非常明顯在類層次上, 我可以橫向的擴充ConcreteComponent的功能(增加ConcreteDecorator類). 如果使用縱向擴充(類繼承), 一條長長的類繼承鍊, That's not a good idea.
3. Decorator中定義的是一個Component指針, 而不是一個ConcreteComponent指針, 也就是Decorator不是針對某個ConcreteComponent類擴充, 而是可以針對所有的ConcreteComponent來擴充.(這一點可以區分Proxy代理模式: 它就是針對某個類的)
4. ConcreteDecorator::Operation中你可以根據你的需求随便修改, 甚至Decorator::Operation你也可以不調用, 看需求吧.
七. 相關模式
1. Adapter模式:Decorator模式不同于Adapter模式, 因為裝飾僅改變對象的職責而不改變它的接口; 而擴充卡将給對象一個全新的接口.
2. Composite模式: 可以将裝飾視為一個退化的, 僅有一個元件的組合. 然而, 裝飾僅給對象添加一些額外的職責—它的目的不在于對象聚集.
3. Strategy模式: 用一個裝飾你可以改變對象的外表; 而Strategy模式使得你可以改變對象的核心. 這是改變對象的兩種途徑.