posts - 5,  comments - 0,  trackbacks - 0

          JDK為程序員提供了大量的類庫,而為了保持類庫的可重用性,可擴展性和靈活性,其中使用到了大量的設計模式,本文將介紹JDKI/O包中使用到的Decorator模式,并運用此模式,實現一個新的輸出流類。Decorator模式簡介

          Decorator模式又名包裝器(Wrapper),它的主要用途在于給一個對象動態的添加一些額外的職責。與生成子類相比,它更具有靈活性。有時候,我們需要為一個對象而不是整個類添加一些新的功能,比如,給一個文本區添加一個滾動條的功能。我們可以使用繼承機制來實現這一功能,但是這種方法不夠靈活,我們無法控制文本區加滾動條的方式和時機。而且當文本區需要添加更多的功能時,比如邊框等,需要創建新的類,而當需要組合使用這些功能時無疑將會引起類的爆炸。

          我們可以使用一種更為靈活的方法,就是把文本區嵌入到滾動條中。而這個滾動條的類就相當于對文本區的一個裝飾。這個裝飾(滾動條)必須與被裝飾的組件(文本區)繼承自同一個接口,這樣,用戶就不必關心裝飾的實現,因為這對他們來說是透明的。裝飾會將用戶的請求轉發給相應的組件(即調用相關的方法),并可能在轉發的前后做一些額外的動作(如添加滾動條)。通過這種方法,我們可以根據組合對文本區嵌套不同的裝飾,從而添加任意多的功能。這種動態的對對象添加功能的方法不會引起類的爆炸,也具有了更多的靈活性。

          以上的方法就是Decorator模式,它通過給對象添加裝飾來動態的添加新的功能。如下是Decorator模式的UML圖:

          Component為組件和裝飾的公共父類,它定義了子類必須實現的方法。

          ConcreteComponent是一個具體的組件類,可以通過給它添加裝飾來增加新的功能。

          一個對于Component的引用,以便將用戶的請求轉發給Component,并可能在轉發請求前后執行一些附加的動作。

          ConcreteDecoratorAConcreteDecoratorB是具體的裝飾,可以使用它們來裝飾具體的Component。

          Java IO包中的Decorator模式

          JDK提供的java.io包中使用了Decorator模式來實現對各種輸入輸出流的封裝。以下將以java.io.OutputStream及其子類為例,討論一下Decorator模式在IO中的使用。

          首先來看一段用來創建IO流的代碼:

                  try {
                      OutputStream out 
          = new DataOutputStream(new FileOutputStream("test.txt")); 
                  } 
          catch (FileNotFoundException e) { 
                      e.printStackTrace(); 
                  }

          這段代碼對于使用過JAVA輸入輸出流的人來說再熟悉不過了,我們使用DataOutputStream封裝了一個FileOutputStream。這是一個典型的Decorator模式的使用,FileOutputStream相當于Component,DataOutputStream就是一個Decorator。將代碼改成如下,將會更容易理解:

                  try { 
                      OutputStream out 
          = new FileOutputStream("test.txt"); 
                      out 
          = new DataOutputStream(out); 
                  } 
          catch(FileNotFoundException e) { 
                      e.printStackTrace(); 
                  }

          由于FileOutputStreamDataOutputStream有公共的父類OutputStream,因此對對象的裝飾對于用戶來說幾乎是透明的。下面就來看看OutputStream及其子類是如何構成Decorator模式的:

          OutputStream是一個抽象類,它是所有輸出流的公共父類,其源代碼如下:

          public abstract class OutputStream implements Closeable, Flushable {

          public abstract void write(int b) throws IOException;

          ...

                }

          它定義了write(int b)的抽象方法。這相當于Decorator模式中的Component類。 ByteArrayOutputStream,FileOutputStream PipedOutputStream 三個類都直接從OutputStream繼承,以ByteArrayOutputStream為例:

          public class ByteArrayOutputStream extends OutputStream { 
          protected byte buf[]; 
          protected int count; 
          public ByteArrayOutputStream() { 
          this(32); 

          public ByteArrayOutputStream(int size) { 
          if (size 〈 0) { 
          throw new IllegalArgumentException("Negative initial size: " + size); 

          buf 
          = new byte[size]; 

          public synchronized void write(int b) { 
          int newcount = count + 1
          if (newcount 〉 buf.length) { 
          byte newbuf[] = new byte[Math.max(buf.length 〈〈 1, newcount)]; 
          System.arraycopy(buf, 
          0, newbuf, 0, count); 
          buf 
          = newbuf; 

          buf[count] 
          = (byte)b; 
          count 
          = newcount; 

           
          }

          它實現了OutputStream中的write(int b)方法,因此我們可以用來創建輸出流的對象,并完成特定格式的輸出。它相當于Decorator模式中的ConcreteComponent類。接著來看一下FilterOutputStream,代碼如下:

          public class FilterOutputStream extends OutputStream { 
          protected OutputStream out; 
          public FilterOutputStream(OutputStream out) { 
          this.out = out; 

          public void write(int b) throws IOException { 
          out.write(b); 

           
          }

          同樣,它也是從OutputStream繼承。但是,它的構造函數很特別,需要傳遞一個OutputStream的引用給它,并且它將保存對此對象的引用。而如果沒有具體的OutputStream對象存在,我們將無法創建FilterOutputStream。由于out既可以是指向FilterOutputStream類型的引用,也可以是指向ByteArrayOutputStream等具體輸出流類的引用,因此使用多層嵌套的方式,我們可以為ByteArrayOutputStream添加多種裝飾。這個FilterOutputStream類相當于Decorator模式中的Decorator類,它的write(int b)方法只是簡單的調用了傳入的流的write(int b)方法,而沒有做更多的處理,因此它本質上沒有對流進行裝飾,所以繼承它的子類必須覆蓋此方法,以達到裝飾的目的。

          BufferedOutputStream DataOutputStreamFilterOutputStream的兩個子類,它們相當于Decorator模式中的ConcreteDecorator,并對傳入的輸出流做了不同的裝飾。以BufferedOutputStream類為例:

          public class BufferedOutputStream extends FilterOutputStream { 
           
          private void flushBuffer() throws IOException { 
          if (count 〉 0) { 
          out.write(buf, 
          0, count); 
          count 
          = 0


          public synchronized void write(int b) throws IOException { 
          if (count 〉= buf.length) { 
          flushBuffer(); 

          buf[count
          ++= (byte)b; 

           
          }

          這個類提供了一個緩存機制,等到緩存的容量達到一定的字節數時才寫入輸出流。首先它繼承了FilterOutputStream,并且覆蓋了父類的write(int b)方法,在調用輸出流寫出數據前都會檢查緩存是否已滿,如果未滿,則不寫。這樣就實現了對輸出流對象動態的添加新功能的目的。

          下面,將使用Decorator模式,為IO寫一個新的輸出流。自己寫一個新的輸出流。

          了解了OutputStream及其子類的結構原理后,我們可以寫一個新的輸出流,來添加新的功能。這部分中將給出一個新的輸出流的例子,它將過濾待輸出語句中的空格符號。比如需要輸出"java io OutputStream",則過濾后的輸出為"javaioOutputStream"。以下為SkipSpaceOutputStream類的代碼:
          package cn.albert.ling.io;

          import java.io.FilterOutputStream;
          import java.io.IOException;
          import java.io.OutputStream;

          public class SkipSpaceOutputStream extends FilterOutputStream {

              
          /**
               * author: albert ling
               * mailto: ling.albert.cn@gamil.com
               * time: 2009-2-23 20:10
               
          */
              
          public SkipSpaceOutputStream(OutputStream out) {
                  
          super(out);
                  
          // TODO Auto-generated constructor stub
              }
              
          public void write(int b) throws IOException{ 
                                  
                  
          if(b != ' '){
                      
          super.write(b);
                  }                      
              } 

          }
          package cn.albert.ling.io;

          import java.io.BufferedInputStream;
          import java.io.DataInputStream;
          import java.io.DataOutputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.OutputStream;

          public class TextSkip {

              
              
          /**
               * author: albert ling
               * mailto: ling.albert.cn@gamil.com
               * time: 2009-2-23 20:10
               
          */
              
          public static void main(String[] args) {
                  
          // TODO Auto-generated method stub

                  
          byte[] buffer = new byte[1024];
                  InputStream in 
          = new BufferedInputStream(new DataInputStream(System.in)); 
                  OutputStream out 
          = new SkipSpaceOutputStream(new DataOutputStream(System.out)); 
                  
          try { 
                      System.out.println(
          "Please input your words: "); 
                      
          int n = in.read(buffer,0,buffer.length); 
                      
          for(int i=0;i<n;i++){ 
                          out.write(buffer[i]); 
                      } 
                  } 
          catch (IOException e) { 
                      e.printStackTrace(); 
                  } 
              }
          }

          執行以上測試程序,將要求用戶在console窗口中輸入信息,程序將過濾掉信息中的空格,并將最后的結果輸出到console窗口。

          比如:以下是引用片段

          Please input your words:

          a b c d e f

           abcdef

          java.io包中,不僅OutputStream用到了Decorator設計模式,InputStream,Reader,Writer等都用到了此模式。而作為一個靈活的,可擴展的類庫,JDK中使用了大量的設計模式,比如在Swing包中的MVC模式,RMI中的Proxy模式等等。對于JDK中模式的研究不僅能加深對于模式的理解,而且還有利于更透徹的了解類庫的結構和組成。




           


           

          posted on 2009-02-23 20:45 Albert Ling 閱讀(477) 評論(0)  編輯  收藏 所屬分類: 設計模式

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2009年2月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          1234567


          路需要自己來走
          MSN:ling.albert.cn@hotmail.com

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          關注Blog

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 土默特右旗| 贞丰县| 重庆市| 镇江市| 泽州县| 黄山市| 荔波县| 日土县| 翼城县| 东平县| 达日县| 阿鲁科尔沁旗| 巴楚县| 红桥区| 滦南县| 饶平县| 平江县| 吴川市| 湖南省| 浙江省| 子长县| 措勤县| 永春县| 太仆寺旗| 章丘市| 托里县| 江川县| 湖北省| 安庆市| 富宁县| 诏安县| 云林县| 忻城县| 安西县| 大田县| 成都市| 墨玉县| 滨海县| 南漳县| 民县| 宜宾市|