java io中的Decorator模式

來源:互聯網
上載者:User
JDK為程式員提供了大量的類庫,而為了保持類庫的可重用性,可擴充性和靈活性,其中使用到了大量的設計模式,本文將介紹JDK的I/O包中使用到的Decorator模式,並運用此模式,實現一個新的輸出資料流類。

  Decorator模式簡介

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

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

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

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

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

  Decorator是所有裝飾的公用父類,它定義了所有裝飾必須實現的方法,同時,它還儲存了一個對於Component的引用,以便將使用者的請求轉寄給Component,並可能在轉寄請求前後執行一些附加的動作。

  ConcreteDecoratorA和ConcreteDecoratorB是具體的裝飾,可以使用它們來裝飾具體的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.printStatckTrace();
}

  由於FileOutputStream和DataOutputStream有公用的父類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 和 DataOutputStream是FilterOutputStream的兩個子類,它們相當於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類的代碼:

  以下是程式碼片段:

  import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* A new output stream, which will check the space character
* and won’t write it to the output stream.
* @author Magic
*
*/
public class SkipSpaceOutputStream extends FilterOutputStream {
  public SkipSpaceOutputStream(OutputStream out) {
   super(out);
  }
  /**
  * Rewrite the method in the parent class, and
  * skip the space character.
  */
  public void write(int b) throws IOException{
   if(b!=’ ’){
    super.write(b);
   }
  }
}

  它從FilterOutputStream繼承,並且重寫了它的write(int b)方法。在write(int b)方法中首先對輸入字元進行了檢查,如果不是空格,則輸出。

  以下是一個測試程式:

  以下是程式碼片段:

  import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Test the SkipSpaceOutputStream.
* @author Magic
*
*/
public class Test {
  public static void main(String[] args){
   byte[] buffer = new byte[1024];
   /**
   * Create input stream from the standard input.
   */
   InputStream in = new BufferedInputStream(new DataInputStream(System.in));
   /**
   * write to the standard output.
   */
   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中模式的研究不僅能加深對於模式的理解,而且還有利於更透徹的瞭解類庫的結構和組成。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.