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

Java設計模式之修飾模式篇

2013-11-23 19:45:49  來源: Java高級技術 

  最近我給女朋友買了一款可以更換外殼的手機現在的外殼是紅色的如果我想用這款手機的時候會更換成銀灰色的外殼但是我不能隨意更換天線或者話筒因為這些功能模塊在手機生產的時候就已經被固定了
  
  軟件中的修飾者(decorator)和手機的外殼一樣封裝了一些可以替換的功能例如下面是一段替換Swing中表模型的代碼
  
  TableSortDecorator sortDecorator = new TableSortDecorator(tablegetModel());
  tablesetModel(sortDecorator);
  
  
  
  在這段代碼中程序首先將表模型包裝在一個修飾對象中以後當表對它的模型進行操作的時候它實際上操作的是排序修飾對象(sortDecorator)該修飾對象在表模型中加入了排序功能而將其他基本的功能委托給缺省的表模型在修飾模型中這個缺省的表模型又被稱為真實對象(real subject)
  
  在Java的編程中基類和子類的繼承關系在編譯的時候就被固定了就像手機的天線和話筒一樣由於繼承關系是靜態的開發人員無法在程序運行時改變對象的行為但是通過修飾者開發人員可以在運行時拼裝對象因此修飾模式提供了一種比繼承更靈活的功能擴充模式
  
  
  修飾模式(Decorator Pattern)
  
  
  在運行時將特定的功能綁定在對象上這就是修飾模式的核心修飾模式比繼承更加靈活因為後者是在編譯時就將特定的功能綁定到類上
  
  下面然我們來看一個簡單的I/O例子
  
  FileReader    frdr = new FileReader(filename);
  LineNumberReader lrdr = new LineNumberReader(frdr);
  
  
  
  這段代碼中創建了一個Readerlrdr它從一個文件中讀取數據並跟蹤文件的行號在第一行創建的frdr對象能夠從文件中讀取數據而第二行給lrdr增加了跟蹤行號的功能在運行時(runtime)修飾者將方法調用傳遞給它所修飾的真實對象在上面的例子中lrdr將方法調用傳遞給它修飾的真實對象frdr修飾者除了能夠進行方法傳遞外還能夠增加類的功能例如在上面的例子中lrdr能夠跟蹤當前的文件流讀入數據的行號
  
  而下面的例子顯示了如何在程序中使用修飾者lrdr程序將數據按行從文件中讀出後加上行號輸出到屏幕上
  
  try {
  LineNumberReader lrdr = new LineNumberReader(new FileReader(filename));
  
  for(String line; (line = lrdrreadLine()) != null;)rticletxt {
   Systemoutprint(lrdrgetLineNumber() + :\t + line);
  }
  }
  catch(javaioFileNotFoundException fnfx) {
  fnfxprintStackTrace();
  }
  catch(javaioIOException iox) {
  ioxprintStackTrace();
  }
  
  修飾者的靜態和動態特性
  
  
  工程學上經常提到靜態和動態的概念靜態方法研究那些變化或位移相對較小的對象例如橋梁或建築而動態方法研究那些變化和移動較快的對象例如發動機在軟件工程中也有相應的概念靜態方法研究在編譯時類之間的關系而動態方法研究在運行時類參與的一些的事件在這一節中我將用UML類圖來展示修飾者的靜態特性用UML時序圖來展示修飾者的動態特性
  
  修飾者的靜態特性
  
  修飾者通過增加功能來修飾被修飾對象(Decorated也就是真實對象)下面的UML類圖展示了修飾者和真實對象之間的關系
   
  圖 修飾者和被修飾者的關系
  
  
  修飾者繼承了被修飾者或者實現了被修飾者的接口同時修飾者還保存了對被修飾者實例的引用這個實例就是修飾者修飾的對象為了說明這些類在到底是如何關聯的中舉了一個Java SDK的javaiopackage中的實際例子
   
  圖 一個真實的修飾模型例子
  
  
  BufferedReader和FilterReader就是圖中演示的抽象類他們都繼承了抽象類Reader並且將方法調用傳遞給Reader對象由於繼承了修飾者類因此LineNumberReader和PushbackReader也是修飾者類
  
  修飾者的動態特性
  
  在運行時修飾者將方法調用傳遞給被修飾者如圖所示
   
  圖 修飾者的動態特性
  
  修飾者通常將對被修飾者的調用包裝起來描述了這種特性描述了上面的I/O例子中修飾者的動態特性
   
  圖 I/O例子中修飾者的動態特性
  
  
  現在大家對修飾模式以及它的靜態和動態特性有一個比較明確的認識了讓我們通過一個完整的例子來說明如何在代碼中實現修飾模式
  
  排序和過濾修飾
  
  修飾者主要是用於給被修飾者增加功能在下面的例子中我們會給Swing中的表增加排序和過濾的功能在介紹例子之前先簡單介紹一下如何使用Swing中的JTable類
  
  import javaxswing*;
  import javaxswingtable*;
  public class Test extends JFrame {
  public static void main(String args[]) {
   Test frame = new Test();
   framesetTitle(Swing表的例子);
   framesetBounds( );
   framesetDefaultCloseOperation(JFrameDISPOSE_ON_CLOSE);
   frameshow();
  }
  public Test() {
   TableModel model = new TestModel(); 
   getContentPane()add(new JScrollPane(new JTable(model)));
  }
  private static class TestModel extends AbstractTableModel {
   final int rows = cols = ;
   public int  getRowCount()  { return rows; }
   public int  getColumnCount() { return cols; }
   public Object getValueAt(int row int col) {
     return ( + row + + col + );
   }
  }
  }
  
  該程序創建了一個×的表表對象由三個部分組成表模型視圖和事件控制器表中的數據保存在表模型中視圖控制數據的顯示而事件控制器控制對事件的響應是運行這個程序的結果
   
  圖 Swing表的例子
  
  排序修飾者
  
  圖中的應用程序包含了一張兩列的表一列是貨物名稱一列是價格通過單擊列頭可以根據貨物的價格對表進行排序下面是這個程序的代碼
   
  圖 排序修飾者的例子
  
  //Testjava
  import javaawt*;
  import javaawtevent*;
  
  import javautilLocale;
  import javautilResourceBundle;
  
  import javaxswing*;
  import javaxswingtable*;
  
  public class Test extends JFrame {
  public static void main(String args[]) {
   SwingApplaunch(new Test() 排序修飾者
                  );
  }
  public Test() {
   // 生成修飾者的實例該實例用於修飾Swing Table原有的表模型
   // 該實例必須是final的因為它會被內嵌類引用
   final TableSortDecorator decorator =
      new TableBubbleSortDecorator(tablegetModel());
   // 將表的模型設定為修飾者因為修飾者實現了TableModel接口
   // 因此Swing Table對象不知道修飾者和真實對象之間的差別
   tablesetModel(decorator);
   getContentPane()add(new JScrollPane(table)
                BorderLayoutCENTER);
   // 在界面中添加一個狀態區
   getContentPane()add(SwingAppgetStatusArea()
                BorderLayoutSOUTH);
   SwingAppshowStatus(進行排序前);
   // 獲得對表中列頭的引用
   JTableHeader hdr = (JTableHeader)tablegetTableHeader();
   // 當單擊鼠標單擊列頭時調用修飾者的sort()方法
   hdraddMouseListener(new MouseAdapter() {
     public void mouseClicked(MouseEvent e) {
      TableColumnModel tcm = tablegetColumnModel();
      int vc = tcmgetColumnIndexAtX(egetX());
      int mc = nvertColumnIndexToModel(vc);
      // 進行排序
      decoratorsort(mc);
      // 更新狀態區
      SwingAppshowStatus(headers[mc] + 排序中);
     }
   });
  }
  final String[] headers = { 品名 價格/每斤 };
  JTable table = new JTable(new Object[][] {
      {蘋果   } {芒果  }
      {檸檬 }{香蕉 }
      {桔子   }
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27419.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.