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

Java I/O 包中的Decorator模式介紹

2022-06-13   來源: Java高級技術 
JDK為程序員提供了大量的類庫而為了保持類庫的可重用性可擴展性和靈活性其中使用到了大量的設計模式本文將介紹JDK的I/O包中使用到的Decorator模式並運用此模式實現一個新的輸出流類

Decorator模式簡介

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

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

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

  


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

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

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

  ConcreteDecoratorA和ConcreteDecoratorB是具體的裝飾可以使用它們來裝飾具體的Component

 Java IO包中的Decorator模式

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

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


  以下是代碼片段
try {
 OutputStream out = new DataOutputStream(new FileOutputStream(testtxt));
} catch (FileNotFoundException e) {
 eprintStackTrace();
}

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


  以下是代碼片段
try {
 OutputStream out = new FileOutputStream(testtxt);
 out = new DataOutputStream(out);
} catch(FileNotFoundException e) {
 eprintStatckTrace();
}

  由於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類

  ByteArrayOutputStreamFileOutputStream 和 PipedOutputStream 三個類都直接從OutputStream繼承以ByteArrayOutputStream為例

  以下是代碼片段
public class ByteArrayOutputStream extends OutputStream {
protected byte buf[];
protected int count;
public ByteArrayOutputStream() {
this();
}
public ByteArrayOutputStream(int size) {
if (size 〈 ) {
throw new IllegalArgumentException(Negative initial size: + size);
}
buf = new byte[size];
}
public synchronized void write(int b) {
int newcount = count + ;
if (newcount 〉 buflength) {
byte newbuf[] = new byte[Mathmax(buflength 〈〈 newcount)];
Systemarraycopy(buf newbuf 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) {
thisout = out;
}
public void write(int b) throws IOException {
outwrite(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 〉 ) {
outwrite(buf count);
count = ;
}
}
public synchronized void write(int b) throws IOException {
if (count 〉= buflength) {
flushBuffer();
}
buf[count++] = (byte)b;
}

}

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

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

 自己寫一個新的輸出流

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

  以下是代碼片段
import javaioFilterOutputStream;
import javaioIOException;
import javaioOutputStream;
/**
* A new output stream which will check the space character
* and wont 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!= ){
   superwrite(b);
  }
 }
}

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

  以下是一個測試程序

  以下是代碼片段
import javaioBufferedInputStream;
import javaioDataInputStream;
import javaioDataOutputStream;
import javaioIOException;
import javaioInputStream;
import javaioOutputStream;
/**
* Test the SkipSpaceOutputStream
* @author Magic
*
*/
public class Test {
 public static void main(String[] args){
  byte[] buffer = new byte[];

  /**
  * Create input stream from the standard input
  */
  InputStream in = new BufferedInputStream(new DataInputStream(Systemin));

  /**
  * write to the standard output
  */
  OutputStream out = new SkipSpaceOutputStream(new DataOutputStream(Systemout));

  try {
   Systemoutprintln(Please input your words: );
   int n = inread(bufferbufferlength);
   for(int i=;i〈n;i++){
    outwrite(buffer[i]);
   }
  } catch (IOException e) {
   eprintStackTrace();
  }
 }
}

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

  以下是引用片段
Please input your words:
a b c d e f
abcdef

總 結

  在javaio包中不僅OutputStream用到了Decorator設計模式InputStreamReaderWriter等都用到了此模式而作為一個靈活的可擴展的類庫JDK中使用了大量的設計模式比如在Swing包中的MVC模式RMI中的Proxy模式等等對於JDK中模式的研究不僅能加深對於模式的理解而且還有利於更透徹的了解類庫的結構和組成
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27522.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.