使用Decorator模式 Java程序員知道可以通過擴展一個類來改變類的行為和擴展一個類的功能
這個行為被稱為繼承
它是面向對象編程的一個重要的特性
舉例來說
如果你想得到一個帶有邊框的Swing類型標簽
你可以子類化javax
swing
JLabel類
然而
子類化並不總是有效
當繼承不能解決問題的時候
你不得不求助與其它的方式
比如
使用Decorator模式
這篇文章解釋了Decorator模式是什麼
並說明什麼時候應該子類化
什麼時候應該采用Decorate模式
在Java語言中關鍵字extends被提供來子類化(擴展)一個類
具有豐富的面向對象編程經驗的程序員知道子類化的威力
通過擴展一個類
我們能夠改變這個類的行為
以列表
所講的JBorderLabel類為例
它擴展了javax
swing
JLabel類
除了多了一個邊框
它和JLabel類具有相同的外觀和行為
the JBorderLabel class
an example of subclassing
package decorator;
import java
awt
Graphics;
import javax
swing
JLabel;
import javax
swing
Icon;
public class JBorderLabel extends JLabel {
public JBorderLabel() {
super();
}
public JBorderLabel(String text) {
super(text);
}
public JBorderLabel(Icon image) {
super(image);
}
public JBorderLabel(String text
Icon image
int horizontalAlignment) {
super(text
image
horizontalAlignment);
}
public JBorderLabel(String text
int horizontalAlignment) {
super(text
horizontalAlignment);
}
protected void paintComponent(Graphics g) {
super
paintComponent(g);
int height = this
getHeight();
int width = this
getWidth();
g
drawRect(
width
height
);
}
}
要理解JBorderLabel如何工作
我們首先要了解Swing繪它的組件的原理
JLabel類同其它的Swing組件一樣
繼承至javax
swing
Jcomponent
Swing
它們都是通過調用JComponent組件的paint方法來畫界面
我們可以通過重載JComponent的公開方法paint來修改一個組件畫界面的行為
下面是一個JComponent的paint方法的定義
public void paint(Graphics g)
作為paint方法的參數傳進來的對象Graphics是一個繪圖面板
為了優化繪圖這個操作
paint方法被分割成三個具有保護(protected)屬性的方法
paintComponent
paintBorder
paintChildren
paint方法調用這三個方法同時將它接受到的Graphics實例傳遞給這三個方法
下面是這三個函數的一個聲明
protected void paintComponent(Graphics g)
protected void paintBorder(Graphics g)
protected void paintChildren(Graphics g)
你可以通過重載這些方法來定制你自己的繪制組件的方式
JBorderLabel類重載了javax
swing
JComponent的paintComponent方法
類JborderLabel的paintComponent方法首先調用父類的paintComponent得到一個Jlabel
它保持了自己的長和寬
通過java
awt
Graphics實例的drawRect方法畫一個矩形
圖
顯示了一個JBorderLabel類的一個實例
正如圖所示的一樣
出了多了一個邊框外
它和JLabel外觀是一樣的
這個例子中子類化工作得相當好
我們來看看子類化不合適的案例
如果你打算讓其它的組件都具有同一行為(比如
畫一個邊框)
那麼你必須做很多的子類化操作
在列表
中
子類化看起來很簡單是因為例子中你僅僅需要重載一個方法
當你有太多的子類需要創建時你的代碼將變得很復雜
出錯的機會也增大了
(你必需要復制(reproduce)你的子類需要支持的父類的構造函數
就像JBorderLabel類一樣)
在這個時候
最好的方式是使用Decorator模式
Decorator模式 在Erich Gamma等編寫的《Design Patterns : Elements of Reusable Object
Oriented Software》一書中
Decorator模式被歸類為結構模式
Decorator模式提供了子類化的一個替代方案
子類化和Decorator模式的主要區別是
采用子類化
你同一個類打交道
使用Decorator模式
你可以動態的修改多個對象
當你擴展(Extend)一個類的時候
你對兒子類的改變將會影響到這個兒子類所有的實例
采用Decorator模式
你所作的改變只會影響到你打算改變的那個對象
理解JComponent類對於書寫裝飾者類很重要
我們通過這個裝飾者類來改變Swing組件的用戶界面
在前面部分我解釋了JComponent是如何畫它的用戶界面的
我們可以通過文檔查找來了解這個類的所有的成員
我們要意識到JComponent有子組件
當JComponent被畫的時候
這些子組件也將被畫
創建一個從JComponent擴展過來的Swing裝飾者
這個裝飾者的構造函數接受一個類型為JComponent的參數
可以傳遞任一一個需要改變行為的Swing對象給裝飾者
這個裝飾者將傳進來的這個組件作為自己的子組件
並不是直接將Swing組件增加到JFrame或JPannel或其它容器
而是先將Swing組件添加到修飾者
再把修飾者增加給容器類
因為一個修飾者也是一個JComponent類型的對象
容器不能將他們區分開來
這個裝飾者是這個容器的一個子組件
當容器讓裝飾者重畫的時候
這個裝飾者paint方法將被調用
舉例來說
假設你有一個JLabel類
你打算把它傳給一個稱之為frame
的JFrame類
使用如下相似的代碼
frame
getContentPane()
add(new JLabel(
a label
));用MyDecorator來修飾JLabel的代碼和它很相似
如下
(記住
MyDecorator類的構造函數應該接受一個JComponent類的輸入參數)
frame
getContentPane()
add(new MyDecorator(new JLabel(
a label
)));
這篇文章示例了兩個Decorator模式的例子
第一個例子是BorderDecorator
這個類被用來修飾JComponent
以便讓JComponent具有一個邊框
當把一個由BorderDecorator修飾的JLabel增加到JFrame
這個JLabel看起來就像JBorderLabel的一個實例
這說明
子類化不是必須的
更好的是
你能夠傳遞任何一個Swing組件給BorderDecorator
這些被傳遞的組件都會給予一個邊框
在這個例子中
通過創建了一個類BorderDecorator來改變不同類型的實例的行為
第二個例子是ResizableDecorator
這個裝飾著為每一個傳給它的Swing組件增加一個小按鈕到左上角
當用戶點擊這個按鈕的時候
這個組件將會最小化為這個按鈕
BorderDecorator類 我們以BorderDecorator開始
這個類表示的裝飾者會為Swing組件增加一個邊框
示例代碼如列表
the BorderDecorator class
package decorator;
import javax
swing
JComponent;
import java
awt
Graphics;
import java
awt
Color;
import java
awt
BorderLayout;
public class BorderDecorator extends JComponent {
// decorated component
protected JComponent child;
public BorderDecorator(JComponent component) {
child = component;
this
setLayout(new BorderLayout());
this
add(child);
}
public void paint(Graphics g) {
super
paint(g);
int height = this
getHeight();
int width = this
getWidth();
g
drawRect(
width
height
);
}
}
注意
這個BorderDecorator擴展了JComponent
它的構造函數接受一個JComponet類型的參數
這個BorderDecorator類有一個類型為JComponent的屬性child
它是傳進來的Jcomponent對象的一個引用
構造函數將被修飾的組件賦值給child變量
並且將這個組件作為一個子組件增加給裝飾者
注意
我們使用了BorderLayout作為裝飾者的布局
這意味著被增加的這個JComponent將占據這個裝飾者的整個區域
現在
讓我們關注一下paint方法
它首先調用了父類的paint方法
這-步操作將畫出裝飾者
在第一次得到裝飾者的長寬以後
我們在裝飾者所在區域的邊緣畫一個長方形
Figure
shows a JFrame with three components:
; An instance of JBorderLabel
; A decorated JLabel
; A decorated JCheckBox
Figure
comparing subclassing and the Decorator pattern
JBorderLabel的一個實例和一個被裝飾過的JLabel對象實例從外表看沒有什麼不同
這說明
Decorator模式可以作為子類化的一個替代方案
第三個組件證明
你能夠使用同一個裝飾者去擴展不同對象的實例的行為
從這點來看
裝飾者是一個(超類)superior
因為僅僅需要創建一個類(BorderDecorator)就可以擴張不同類型的多個對象的功能
顯示了圖
中的JFrame類的實現代碼
using the BorderDecorator class
package decorator;
import java
awt
*;
import javax
swing
*;
import java
awt
event
*;
public class Frame
extends JFrame {
JBorderLabel label
=
new JBorderLabel(
JLabel Subclass
);
BorderDecorator label
=
new BorderDecorator(new JLabel(
Decorated JLabel
));
BorderDecorator checkBox
=
new BorderDecorator(new JCheckBox(
Decorated JCheckBox
));
public Frame
() {
try {
this
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPan
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27319.html