国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java設計模式之修飾模式篇

2019-11-18 12:17:38
字體:
來源:轉載
供稿:網友

  最近我給女朋友買了一款可以更換外殼的手機。現在的外殼是紅色的,假如我想用這款手機的時候,會更換成銀灰色的外殼。但是我不能隨意更換天線或者話筒,因為這些功能模塊在手機生產的時候就已經被固定了。
  
  軟件中的修飾者(decorator),和手機的外殼一樣,封裝了一些可以替換的功能。例如下面是一段替換Swing中表模型的代碼:
  
  TableSortDecorator sortDecorator = new TableSortDecorator(table.getModel());
  table.setModel(sortDecorator);
  
  
  
  在這段代碼中,程序首先將表模型包裝在一個修飾對象中。以后當表對它的模型進行操作的時候,它實際上操作的是排序修飾對象(sortDecorator),該修飾對象在表模型中加入了排序功能,而將其他基本的功能委托給缺省的表模型,在修飾模型中,這個缺省的表模型又被稱為真實對象(real subject)。
  
  在java的編程中,基類和子類的繼續關系在編譯的時候就被固定了,就像手機的天線和話筒一樣。由于繼續關系是靜態的,開發人員無法在程序運行時改變對象的行為。但是通過修飾者開發人員可以在運行時拼裝對象,因此修飾模式提供了一種比繼續更靈活的功能擴充模式。
  
  
  修飾模式(Decorator Pattern)
  
  
  在運行時將特定的功能綁定在對象上,這就是修飾模式的核心。修飾模式比繼續更加靈活,因為后者是在編譯時就將特定的功能綁定到類上。
  
  下面然我們來看一個簡單的I/O例子:
  
  FileReader    frdr = new FileReader(filename);
  LineNumberReader lrdr = new LineNumberReader(frdr);
  
  
  
  這段代碼中創建了一個Reader:lrdr。它從一個文件中讀取數據并跟蹤文件的行號。在第一行創建的frdr對象能夠從文件中讀取數據,而第二行給lrdr增加了跟蹤行號的功能。在運行時(runtime),修飾者將方法調用傳遞給它所修飾的真實對象。在上面的例子中,lrdr將方法調用傳遞給它修飾的真實對象frdr。修飾者除了能夠進行方法傳遞外,還能夠增加類的功能。例如在上面的例子中,lrdr能夠跟蹤當前的文件流讀入數據的行號。
  
  而下面的例子顯示了如何在程序中使用修飾者lrdr。程序將數據按行從文件中讀出后,加上行號輸出到屏幕上。
  
  try {
  LineNumberReader lrdr = new LineNumberReader(new FileReader(filename));
  
  for(String line; (line = lrdr.readLine()) != null;)rticle.txt {
   System.out.PRint(lrdr.getLineNumber() + ":/t" + line);
  }
  }
  catch(java.io.FileNotFoundException fnfx) {
  fnfx.printStackTrace();
  }
  catch(java.io.IOException iox) {
  iox.printStackTrace();
  }
  
  修飾者的靜態和動態特性
  
  
  工程學上經常提到靜態和動態的概念。靜態方法研究那些變化或位移相對較小的對象,例如橋梁或建筑,而動態方法研究那些變化和移動較快的對象,例如發動機。在軟件工程中也有相應的概念,靜態方法研究在編譯時類之間的關系,而動態方法研究在運行時類參與的一些的事件。在這一節中,我將用UML類圖來展示修飾者的靜態特性,用UML時序圖來展示修飾者的動態特性。
  
  修飾者的靜態特性
  
  修飾者通過增加功能來修飾被修飾對象(Decorated,也就是真實對象)。下面的UML類圖展示了修飾者和真實對象之間的關系。
   Java設計模式之修飾模式篇(圖一)
  圖1 修飾者和被修飾者的關系
  
  
  修飾者繼續了被修飾者或者實現了被修飾者的接口,同時修飾者還保存了對被修飾者實例的引用,這個實例就是修飾者修飾的對象。為了說明這些類在到底是如何關聯的,圖2中舉了一個Java SDK的java.io.package中的實際例子。
   Java設計模式之修飾模式篇(圖二)
  圖2 一個真實的修飾模型例子
  
  
  BufferedReader和FilterReader就是圖1中演示的抽象類,他們都繼續了抽象類Reader,并且將方法調用傳遞給Reader對象。由于繼續了修飾者類,因此LineNumberReader和PushbackReader也是修飾者類。
  
  修飾者的動態特性
  
  在運行時,修飾者將方法調用傳遞給被修飾者,如圖3所示:
   Java設計模式之修飾模式篇(圖三)
  圖3 修飾者的動態特性
  
  修飾者通常將對被修飾者的調用包裝起來,圖3描述了這種特性。圖4描述了上面的I/O例子中修飾者的動態特性:
   Java設計模式之修飾模式篇(圖四)
  圖4 I/O例子中修飾者的動態特性
  
  
  現在大家對修飾模式以及它的靜態和動態特性有一個比較明確的熟悉了。讓我們通過一個完整的例子來說明如何在代碼中實現修飾模式。
  
  排序和過濾修飾
  
  修飾者主要是用于給被修飾者增加功能。在下面的例子中,我們會給Swing中的表增加排序和過濾的功能。在介紹例子之前,先簡單介紹一下如何使用Swing中的JTable類。
  
  import javax.swing.*;
  import javax.swing.table.*;
  public class Test extends JFrame {
  public static void main(String args[]) {
   Test frame = new Test();
   frame.setTitle("Swing表的例子");
   frame.setBounds(300, 300, 450, 300);
   frame.setDefaultCloSEOperation(JFrame.DISPOSE_ON_CLOSE);
   frame.show();
  }
  public Test() {
   TableModel model = new TestModel(); 
   getContentPane().add(new JScrollPane(new JTable(model)));
  }
  private static class TestModel extends AbstractTableModel {
   final int rows = 100, cols = 10;
   public int  getRowCount()  { return rows; }
   public int  getColumnCount() { return cols; }
   public Object getValueAt(int row, int col) {
     return "(" + row + "," + col + ")";
   }
  }
  }
  
  該程序創建了一個100×10的表。表對象由三個部分組成:表模型、視圖和事件控制器。表中的數據保存在表模型中,視圖控制數據的顯示,而事件控制器控制對事件的響應。圖5是運行這個程序的結果。
   Java設計模式之修飾模式篇(圖五)
  圖5 Swing表的例子
  
  排序修飾者
  
  圖6中的應用程序包含了一張兩列的表,一列是貨物名稱,一列是價格。通過單擊列頭可以根據貨物的價格對表進行排序。下面是這個程序的代碼:
   Java設計模式之修飾模式篇(圖六)
  圖6 排序修飾者的例子
  
  //Test.java
  import java.awt.*;
  import java.awt.event.*;
  
  import java.util.Locale;
  import java.util.ResourceBundle;
  
  import javax.swing.*;
  import javax.swing.table.*;
  
  public class Test extends JFrame {
  public static void main(String args[]) {
   SwingApp.launch(new Test(), "排序修飾者",
                  300, 300, 450, 250);
  }
  public Test() {
   // 生成修飾者的實例,該實例用于修飾Swing Table原有的表模型
   // 該實例必須是final的,因為它會被內嵌類引用。
   final TableSortDecorator decorator =
      new TableBubbleSortDecorator(table.getModel());
   // 將表的模型設定為修飾者。因為修飾者實現了TableModel接口,
   // 因此Swing Table對象不知道修飾者和真實對象之間的差別。
   table.setModel(decorator);
   getContentPane().add(new JScrollPane(table),
                BorderLayout.CENTER);
   // 在界面中添加一個狀態區
   getContentPane().add(SwingApp.getStatusArea(),
                BorderLayout.SOUTH);
   SwingApp.showStatus("進行排序前");
   // 獲得對表中列頭的引用。
   JTableHeader hdr = (JTableHeader)table.getTableHeader();
   // 當單擊鼠標單擊列頭時,調用修飾者的sort()方法。
   hdr.addMouseListener(new MouseAdapter() {
     public void mouseClicked(MouseEvent e) {
      TableColumnModel tcm = table.getColumnModel();
      int vc = tcm.getColumnIndexAtX(e.getX());
      int mc = table.convertColumnIndexToModel(vc);
      // 進行排序
      decorator.sort(mc);
      // 更新狀態區
      SwingApp.showStatus(headers[mc] + " 排序中");
     }
   });
  }
  final String[] headers = { "品名", "價格/每斤." };
  JTable table = new JTable(new Object[][] {
      {"蘋果",   "1.2"}, {"芒果",  "4"},
      {"檸檬", "2.5"},{"香蕉", "0.8"},
      {"桔子",   "1.8"},

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 两当县| 吉安县| 兖州市| 三台县| 宜丰县| 平罗县| 徐州市| 陈巴尔虎旗| 连南| 朝阳区| 宁阳县| 华蓥市| 莱西市| 右玉县| 钦州市| 兰溪市| 芒康县| 两当县| 阳谷县| 白朗县| 抚顺县| 府谷县| 富宁县| 波密县| 屏边| 南安市| 平原县| 修水县| 革吉县| 惠来县| 曲阜市| 塔城市| 七台河市| 凌海市| 兴宁市| 类乌齐县| 房山区| 兴宁市| 南木林县| 申扎县| 凌云县|