熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

使用Decorator模式 翻譯者:Disneytiger

2022-06-13   來源: Java高級技術 

  使用Decorator模式
  Java程序員知道可以通過擴展一個類來改變類的行為和擴展一個類的功能這個行為被稱為繼承它是面向對象編程的一個重要的特性
  舉例來說如果你想得到一個帶有邊框的Swing類型標簽你可以子類化javaxswingJLabel類然而子類化並不總是有效當繼承不能解決問題的時候你不得不求助與其它的方式比如使用Decorator模式
  這篇文章解釋了Decorator模式是什麼並說明什麼時候應該子類化什麼時候應該采用Decorate模式
  在Java語言中關鍵字extends被提供來子類化(擴展)一個類具有豐富的面向對象編程經驗的程序員知道子類化的威力通過擴展一個類我們能夠改變這個類的行為以列表所講的JBorderLabel類為例它擴展了javaxswingJLabel類除了多了一個邊框它和JLabel類具有相同的外觀和行為
  the JBorderLabel class an example of subclassing
  package decorator;
  
  import javaawtGraphics;
  import javaxswingJLabel;
  import javaxswingIcon;
  
  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) {
  superpaintComponent(g);
  int height = thisgetHeight();
  int width = thisgetWidth();
  gdrawRect( width height );
  }
  }
  要理解JBorderLabel如何工作我們首先要了解Swing繪它的組件的原理 JLabel類同其它的Swing組件一樣繼承至javaxswingJcomponentSwing它們都是通過調用JComponent組件的paint方法來畫界面我們可以通過重載JComponent的公開方法paint來修改一個組件畫界面的行為下面是一個JComponent的paint方法的定義
  public void paint(Graphics g)
  作為paint方法的參數傳進來的對象Graphics是一個繪圖面板為了優化繪圖這個操作paint方法被分割成三個具有保護(protected)屬性的方法paintComponent paintBorder paintChildrenpaint方法調用這三個方法同時將它接受到的Graphics實例傳遞給這三個方法下面是這三個函數的一個聲明
  protected void paintComponent(Graphics g)
  protected void paintBorder(Graphics g)
  protected void paintChildren(Graphics g)
  你可以通過重載這些方法來定制你自己的繪制組件的方式
  JBorderLabel類重載了javaxswingJComponent的paintComponent方法類JborderLabel的paintComponent方法首先調用父類的paintComponent得到一個Jlabel它保持了自己的長和寬通過javaawtGraphics實例的drawRect方法畫一個矩形顯示了一個JBorderLabel類的一個實例正如圖所示的一樣出了多了一個邊框外它和JLabel外觀是一樣的
  這個例子中子類化工作得相當好我們來看看子類化不合適的案例如果你打算讓其它的組件都具有同一行為(比如畫一個邊框)那麼你必須做很多的子類化操作在列表子類化看起來很簡單是因為例子中你僅僅需要重載一個方法當你有太多的子類需要創建時你的代碼將變得很復雜出錯的機會也增大了(你必需要復制(reproduce)你的子類需要支持的父類的構造函數就像JBorderLabel類一樣)在這個時候最好的方式是使用Decorator模式
  
  Decorator模式
  在Erich Gamma等編寫的《Design Patterns : Elements of Reusable ObjectOriented 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類使用如下相似的代碼
  framegetContentPane()add(new JLabel(a label));用MyDecorator來修飾JLabel的代碼和它很相似如下(記住MyDecorator類的構造函數應該接受一個JComponent類的輸入參數)
  framegetContentPane()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 javaxswingJComponent;
  import javaawtGraphics;
  import javaawtColor;
  import javaawtBorderLayout;
  
  public class BorderDecorator extends JComponent {
  
  // decorated component
  protected JComponent child;
  
  public BorderDecorator(JComponent component) {
  child = component;
  thissetLayout(new BorderLayout());
  thisadd(child);
  }
  
  public void paint(Graphics g) {
  superpaint(g);
  int height = thisgetHeight();
  int width = thisgetWidth();
  gdrawRect( 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 javaawt*;
  import javaxswing*;
  import javaawtevent*;
  
  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 {
  thissetDefaultCloseOperation(EXIT_ON_CLOSE);
  getContentPan
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27319.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.