小A:“那我們應該如何使用它哩?”
大B:“舉Adapter中的打樁示例,在Adapter中有兩種類:方形樁、圓形樁,Adapter模式展示如何綜合使用這兩個類,在Decorator模式中,我們是要在打樁時增加一些額外功能,比如,挖坑。在樁上釘木板等,不關心如何使用兩個不相關的類。”
我們先建立一個接口:
接口Work有一個具體實現:插入方形樁或圓形樁,這兩個區別對Decorator是無所謂。我們以插入方形樁為例:
大B:“現在有一個應用:需要在樁打入前,挖坑,在打入後,在樁上釘木板,這些額外的功能是動態,可能隨意增加調整修改,比如,可能又需要在打樁之後釘架子,隻是比喻。那麼我們使用Decorator模式,這裏方形樁SquarePeg是decoratee被刷油漆者,我們需要在decoratee上刷些‘油漆’,這些油漆就是那些額外的功能。”
//額外增加的功能被打包在這個List中
//在構造器中使用組合new方式,引入Work對象;
(“挖坑”);
(“釘木板”);
//在新方法中,我們在insert之前增加其他方法,這裏次序先後是用戶靈活指定的
大B:“在剛才講的例子中,我們把挖坑和釘木板都排在了打樁insert前麵,這裏隻是舉例說明額外功能次序可以任意安排。好了,Decorator模式出來了,我們看如何調用。”
Decorator模式至此完成。
大B:“如果你細心,會發現,上麵調用類似我們讀取文件時的調用。”
大B:“實際上Java的I/OAPI就是使用Decorator實現的,I/O變種很多,如果都采取繼承方法,將會產生很多子類,顯然相當繁瑣。Jive中的Decorator實現,在論壇係統中,有些特別的字是不能出現在論壇中如‘打倒XXX’,我們需要過濾這些‘反動’的字體。不讓他們出現或者高亮度顯示。在IBMJava專欄中專門談Jive的文章中,有談及Jive中使用了Decorator模式,其實,該程序並沒有真正使用Decorator。我們在分辨是否真正是Decorator模式,以及會真正使用Decorator模式,一定要把握好Decorator模式的定義,以及其中參與的角色(Decoratee和Decorator)。”
大B:“若你學過麵向對象的php開發,即使很短的時間了解了一些,你會知道,你可以通過繼承改變或者增加一個類的功能,這是所有麵向對象語言的一個基本特性。如果已經存在的一個php類缺少某些方法,或者須要給方法添加更多的功能(魅力),你也許會僅僅繼承這個類來產生一個新類-這建立在額外的代碼上。但是產生子類並不總是可能或是合適的。”
小A:“如果改變一個已經初始化的對象的行為,怎麼辦?或者,繼承許多類的行為,又怎麼辦?”
大B:“前一個,隻能在於運行時完成,後者顯然時可能的,但是可能會導致產生大量的不同的類-可怕的事情。”
小A:“你如何組織你的代碼使其可以容易的添加基本的或者一些很少用到的特性,而不是直接不額外的代碼寫在你的類的內部?”
大B:“裝飾器模式提供了改變子類的靈活方案。裝飾器模式允許你在不引起子類數量爆炸的情況下動態的修飾對象,添加特性。當用於一組子類時,裝飾器模式更加有用。”
小A:“如果擁有一族子類(從一個父類派生而來),需要在與子類獨立使用情況下添加額外的特性,是否可以使用裝飾器模式,以避免代碼重複和具體子類數量的增加?”
大B:“看看以下例子,你可以更好的理解這種觀點。考慮一個建立在組件概念上的‘form’表單庫,在那裏你需要為每一個你想要表現的表單控製類型建立一個類。這種類圖SelectandTextInput類是組件類的子類。假如想要增加一個‘labeled’帶標簽的組件——一個輸入表單告訴你要輸入的內容。因為任何一個表單都可能需要被標記,可能會像這樣繼承每一個具體的組件。”
小A:“確實,裝飾器模式是避免這種情況的好方法。”
大B:“裝飾器模式結構上類似與代理模式。一個裝飾器對象保留有對對象的引用,而且忠實的重新建立被裝飾對象的公共接口。裝飾器也可以增加方法,擴展被裝飾對象的接口,任意重載方法,甚至可以在腳本執行期間有條件的重載方法。”
小A:“那是為什麼?”
大B:“為了探究裝飾器模式,可以用裝飾器模式而不是繼承,實現‘lable’和‘invalidation’兩個特性。”
(本章完)