來源:http://www.cn-java.com/www1/?action-viewnews-itemid-3384
JDK為程序員提供了大量的類庫,而為了保持類庫的可重用性,可擴展性和靈活性,其中使用到了大量的設計模式,本文將介紹JDK的I/O包中使用到的Decorator模式,并運用此模式,實現(xiàn)一個新的輸出流類。
Decorator模式簡介
Decorator模式又名包裝器(Wrapper),它的主要用途在于給一個對象動態(tài)的添加一些額外的職責。與生成子類相比,它更具有靈活性。有時候,我們需要為一個對象而不是整個類添加一些新的功能,比如,給一個文本區(qū)添加一個滾動條的功能。我們可以使用繼承機制來實現(xiàn)這一功能,但是這種方法不夠靈活,我們無法控制文本區(qū)加滾動條的方式和時機。而且當文本區(qū)需要添加更多的功能時,比如邊框等,需要創(chuàng)建新的類,而當需要組合使用這些功能時無疑將會引起類的爆炸。
我們可以使用一種更為靈活的方法,就是把文本區(qū)嵌入到滾動條中。而這個滾動條的類就相當于對文本區(qū)的一個裝飾。這個裝飾(滾動條)必須與被裝飾的組件(文本區(qū))繼承自同一個接口,這樣,用戶就不必關心裝飾的實現(xiàn),因為這對他們來說是透明的。裝飾會將用戶的請求轉發(fā)給相應的組件(即調(diào)用相關的方法),并可能在轉發(fā)的前后做一些額外的動作(如添加滾動條)。通過這種方法,我們可以根據(jù)組合對文本區(qū)嵌套不同的裝飾,從而添加任意多的功能。這種動態(tài)的對對象添加功能的方法不會引起類的爆炸,也具有了更多的靈活性。
以上的方法就是Decorator模式,它通過給對象添加裝飾來動態(tài)的添加新的功能。如下是Decorator模式的UML圖:

Component為組件和裝飾的公共父類,它定義了子類必須實現(xiàn)的方法。
ConcreteComponent是一個具體的組件類,可以通過給它添加裝飾來增加新的功能。
Decorator是所有裝飾的公共父類,它定義了所有裝飾必須實現(xiàn)的方法,同時,它還保存了一個對于Component的引用,以便將用戶的請求轉發(fā)給Component,并可能在轉發(fā)請求前后執(zhí)行一些附加的動作。
ConcreteDecoratorA和ConcreteDecoratorB是具體的裝飾,可以使用它們來裝飾具體的Component。
Java IO包中的Decorator模式
JDK提供的java.io包中使用了Decorator模式來實現(xiàn)對各種輸入輸出流的封裝。以下將以java.io.OutputStream及其子類為例,討論一下Decorator模式在IO中的使用。
首先來看一段用來創(chuàng)建IO流的代碼: 以下是代碼片段:

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


{ e.printStackTrace(); }

這段代碼對于使用過JAVA輸入輸出流的人來說再熟悉不過了,我們使用DataOutputStream封裝了一個FileOutputStream。這是一個典型的Decorator模式的使用,F(xiàn)ileOutputStream相當于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,F(xiàn)ileOutputStream 和 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;
}

}

它實現(xiàn)了OutputStream中的write(int b)方法,因此我們可以用來創(chuàng)建輸出流的對象,并完成特定格式的輸出。它相當于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繼承。但是,它的構造函數(shù)很特別,需要傳遞一個OutputStream的引用給它,并且它將保存對此對象的引用。而如果沒有具體的OutputStream對象存在,我們將無法創(chuàng)建FilterOutputStream。由于out既可以是指向FilterOutputStream類型的引用,也可以是指向ByteArrayOutputStream等具體輸出流類的引用,因此使用多層嵌套的方式,我們可以為ByteArrayOutputStream添加多種裝飾。這個FilterOutputStream類相當于Decorator模式中的Decorator類,它的write(int b)方法只是簡單的調(diào)用了傳入的流的write(int b)方法,而沒有做更多的處理,因此它本質(zhì)上沒有對流進行裝飾,所以繼承它的子類必須覆蓋此方法,以達到裝飾的目的。
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;
}

}

這個類提供了一個緩存機制,等到緩存的容量達到一定的字節(jié)數(shù)時才寫入輸出流。首先它繼承了FilterOutputStream,并且覆蓋了父類的write(int b)方法,在調(diào)用輸出流寫出數(shù)據(jù)前都會檢查緩存是否已滿,如果未滿,則不寫。這樣就實現(xiàn)了對輸出流對象動態(tài)的添加新功能的目的。
下面,將使用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();
}
}
}

執(zhí)行以上測試程序,將要求用戶在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中模式的研究不僅能加深對于模式的理解,而且還有利于更透徹的了解類庫的結構和組成。
------------------------------
奧尚生活: http://www.wanghengliang.cn
南充奧尚軟件: http://www.Aosunsoft.com 南充軟件開發(fā)