Decorator是用於裝飾一個事物(或人)的另一個事物(或人)
一個Decorator直接改變被裝飾對象的職責或特征
但是不能改變被裝飾對象的自有屬性
從我們的專業角度來討論一些存在的實例
JScrollPane可以裝飾JComponent的視圖部分
JComponent本身並不會被改變
但是增加了一個新的屬性(可滾動)
BufferedInputStream是InputStream的裝飾子
本身BufferedInputStream就是一個InputStream
但是它更快
因為提供了對數據的緩存
考慮一下DebugButton
它與JButton一樣
但是它在被點擊時可以向日志文件添加消息
DebugButton是JButton的裝飾子
因為它直接改變了JButton但並沒有改變它的自有屬性
再又如ScrollOverButton
它增加了一個鼠標滑過的行為
當鼠標移出時它是平的
當鼠標經過時它具有一個凸起的邊框
很顯然
ScrollOverButton也是JButton的裝飾子
現在
我們知道Decorator可能有三種不同的實現
繼承(Inheritance)
封裝(Wrapper)
外掛(External)
本文將討論每一個實現模型
以及它們的優缺點
繼承 對於開發人員而言
最直觀的Decorator實現就是
寫一個派生類
它繼承自被裝飾類
並賦於新的職責
新的職責可以是通過增加方法或是修改已有方法來實現
public class DebugButton extends JButton
{
public DebugButton()
{
addActionListener(new ActionListener()
{
System
out
println(
debug message
);
});
}
}
此外
我們也可以用相同的方式來實現ScrollOverButton
不是增加ActionListener
而是增加MouseListener
在MouseListener回調方法中改變JButton的邊框
當mouseEntered()被調用時
將邊框從EmpetyBorder變為RaisedBevelBorder
而當mouseExited()方法被調用時
再將邊框從RaisedBevelBorder恢復成EmpetyBorder
對於BufferedInputStream
同樣實現也是非常簡單的
修改每個讀數據的方法
讓它從內存緩沖區來讀取數據
如果緩沖區是空的
它可以通過super
read()方法來獲取數據並填充緩沖區
JScrollPane
要實現起來就有點復雜
下面我將討論為什麼它會比較難以用繼承的方式來實現
討論一下繼承方式實現Decorator模式的優點與缺點
優點 我們幾乎可以用這個方式實現所有的Decorator
使用繼承方式實現Decorator模式
可以保留被裝飾類的原始類型
這一點是非常重要的
用繼承方式
我們仍可以使用被裝飾類的在被裝飾之前的類型
例如
我們可以在我們的應用程序中使用crollOverButton代替JButton
但是JScrollPane就不能代替包含在它內部的對象
缺點 用繼承的方式仍不夠直接
設想一下我們實現了ScrollOverButton和DebugButton
但是我們又需要實現一個既有ScrollOverButton特點又有DebugButton行為的按鈕
怎麼辦?用繼承方式我們唯一的選擇就是再派生出一個ScrollOverDebugButton類
如果我們有了ScrollOverDebugButton的實現
那麼是否還需要繼續保留ScrollOverButton或DebugButton實現?因為我們可以為ScrollOverDebugButton增加兩對方法來打開或關閉debug或scroll
over的行為
public void setDebug(boolean b);
public boolean isDebug();
public void setScrollOver(boolean b);
public boolean isScrollOver();
再進一步考慮
如果將來我們有更多的裝飾功能
增加新的U
U
Un個行為
我們是不是要寫一個類
叫U
U
UnButton?它是不是要包括
n個這樣的方法
public void setU(boolean b);
public boolean getU;();
每增加一個新的行為(Un+
)給裝飾器就需要增加兩個新的方法
並要修改這個裝飾器的代碼實現
這明顯與面向對象的思想相悖
可能會產生嚴重的後果
(注意
javax
swing
JButton就是這樣實現的)
多數可視化對象的行為是由風格參數來指定的
而風格的改變是不可預知的
當風格發生了改變
我們不得不調整自己的改變
正如上面所述
使用繼承的方式可能需要改變實現的代碼
要保證被裝飾類的原始類型也不是一件容易的事
我們需要重載每個構造子
有時甚至是靜態方式
盡管這不困難
但總是相當麻煩的一件事
用繼承方式來實現Decorator模式並不象我們先前想像的那麼簡單
許多時候
我們並不知道將來我們需要哪一些裝飾器
結果是
使用繼承方式的Decorator在擴展性方面相當困難
並且與面向對象的原則會產生沖突
From:http://tw.wingwit.com/Article/program/Java/Javascript/201311/25290.html