JAVA & XML & JAVASCRIPT & AJAX & CSS

          Web 2.0 技術(shù)儲(chǔ)備............

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            77 隨筆 :: 17 文章 :: 116 評(píng)論 :: 0 Trackbacks

          http://java.chinaitlab.com/model/39095.html

          JDK為程序員提供了大量的類(lèi)庫(kù),而為了保持類(lèi)庫(kù)的可重用性,可擴(kuò)展性和靈活性,其中使用到了大量的設(shè)計(jì)模式,本文將介紹JDK的I/O包中使用到的Decorator模式,并運(yùn)用此模式,實(shí)現(xiàn)一個(gè)新的輸出流類(lèi)。

            Decorator模式簡(jiǎn)介

            Decorator模式又名包裝器(Wrapper),它的主要用途在于給一個(gè)對(duì)象動(dòng)態(tài)的添加一些額外的職責(zé)。與生成子類(lèi)相比,它更具有靈活性。
          有時(shí)候,我們需要為一個(gè)對(duì)象而不是整個(gè)類(lèi)添加一些新的功能,比如,給一個(gè)文本區(qū)添加一個(gè)滾動(dòng)條的功能。我們可以使用繼承機(jī)制來(lái)實(shí)現(xiàn)這一功能,但是這種方法不夠靈活,我們無(wú)法控制文本區(qū)加滾動(dòng)條的方式和時(shí)機(jī)。而且當(dāng)文本區(qū)需要添加更多的功能時(shí),比如邊框等,需要?jiǎng)?chuàng)建新的類(lèi),而當(dāng)需要組合使用這些功能時(shí)無(wú)疑將會(huì)引起類(lèi)的爆炸。

            我們可以使用一種更為靈活的方法,就是把文本區(qū)嵌入到滾動(dòng)條中。而這個(gè)滾動(dòng)條的類(lèi)就相當(dāng)于對(duì)文本區(qū)的一個(gè)裝飾。這個(gè)裝飾(滾動(dòng)條)必須與被裝飾的組件(文本區(qū))繼承自同一個(gè)接口,這樣,用戶(hù)就不必關(guān)心裝飾的實(shí)現(xiàn),因?yàn)檫@對(duì)他們來(lái)說(shuō)是透明的。裝飾會(huì)將用戶(hù)的請(qǐng)求轉(zhuǎn)發(fā)給相應(yīng)的組件(即調(diào)用相關(guān)的方法),并可能在轉(zhuǎn)發(fā)的前后做一些額外的動(dòng)作(如添加滾動(dòng)條)。通過(guò)這種方法,我們可以根據(jù)組合對(duì)文本區(qū)嵌套不同的裝飾,從而添加任意多的功能。這種動(dòng)態(tài)的對(duì)對(duì)象添加功能的方法不會(huì)引起類(lèi)的爆炸,也具有了更多的靈活性。

            以上的方法就是Decorator模式,它通過(guò)給對(duì)象添加裝飾來(lái)動(dòng)態(tài)的添加新的功能。如下是Decorator模式的UML圖:


            Component為組件和裝飾的公共父類(lèi),它定義了子類(lèi)必須實(shí)現(xiàn)的方法。

            ConcreteComponent是一個(gè)具體的組件類(lèi),可以通過(guò)給它添加裝飾來(lái)增加新的功能。

            Decorator是所有裝飾的公共父類(lèi),它定義了所有裝飾必須實(shí)現(xiàn)的方法,同時(shí),它還保存了一個(gè)對(duì)于Component的引用,以便將用戶(hù)的請(qǐng)求轉(zhuǎn)發(fā)給Component,并可能在轉(zhuǎn)發(fā)請(qǐng)求前后執(zhí)行一些附加的動(dòng)作。

            ConcreteDecoratorA和ConcreteDecoratorB是具體的裝飾,可以使用它們來(lái)裝飾具體的Component。

            Java IO包中的Decorator模式

            JDK提供的java.io包中使用了Decorator模式來(lái)實(shí)現(xiàn)對(duì)各種輸入輸出流的封裝。以下將以java.io.OutputStream及其子類(lèi)為例,討論一下Decorator模式在IO中的使用。

            首先來(lái)看一段用來(lái)創(chuàng)建IO流的代碼:


            以下是代碼片段:
          try {
           OutputStream out = new DataOutputStream(new FileOutputStream("test.txt"));
          } catch (FileNotFoundException e) {
           e.printStackTrace();
          }

            這段代碼對(duì)于使用過(guò)JAVA輸入輸出流的人來(lái)說(shuō)再熟悉不過(guò)了,我們使用DataOutputStream封裝了一個(gè)FileOutputStream。這是一個(gè)典型的Decorator模式的使用,F(xiàn)ileOutputStream相當(dāng)于Component,DataOutputStream就是一個(gè)Decorator。將代碼改成如下,將會(huì)更容易理解:


            以下是代碼片段:
          try {
           OutputStream out = new FileOutputStream("test.txt");
           out = new DataOutputStream(out);
          } catch(FileNotFoundException e) {
           e.printStatckTrace();
          }

            由于FileOutputStream和DataOutputStream有公共的父類(lèi)OutputStream,因此對(duì)對(duì)象的裝飾對(duì)于用戶(hù)來(lái)說(shuō)幾乎是透明的。下面就來(lái)看看OutputStream及其子類(lèi)是如何構(gòu)成Decorator模式的:


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

            以下是代碼片段:
          public abstract class OutputStream implements Closeable, Flushable {
          public abstract void write(int b) throws IOException;
          ...
          }

            它定義了write(int b)的抽象方法。這相當(dāng)于Decorator模式中的Component類(lèi)。

            ByteArrayOutputStream,F(xiàn)ileOutputStream 和 PipedOutputStream 三個(gè)類(lèi)都直接從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;
          }
          ...
          }

            它實(shí)現(xiàn)了OutputStream中的write(int b)方法,因此我們可以用來(lái)創(chuàng)建輸出流的對(duì)象,并完成特定格式的輸出。它相當(dāng)于Decorator模式中的ConcreteComponent類(lèi)。

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

            BufferedOutputStream 和 DataOutputStream是FilterOutputStream的兩個(gè)子類(lèi),它們相當(dāng)于Decorator模式中的ConcreteDecorator,并對(duì)傳入的輸出流做了不同的裝飾。以BufferedOutputStream類(lèi)為例:

            以下是代碼片段:
          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;
          }
          ...
          }

            這個(gè)類(lèi)提供了一個(gè)緩存機(jī)制,等到緩存的容量達(dá)到一定的字節(jié)數(shù)時(shí)才寫(xiě)入輸出流。首先它繼承了FilterOutputStream,并且覆蓋了父類(lèi)的write(int b)方法,在調(diào)用輸出流寫(xiě)出數(shù)據(jù)前都會(huì)檢查緩存是否已滿(mǎn),如果未滿(mǎn),則不寫(xiě)。這樣就實(shí)現(xiàn)了對(duì)輸出流對(duì)象動(dòng)態(tài)的添加新功能的目的。

            下面,將使用Decorator模式,為IO寫(xiě)一個(gè)新的輸出流。

            自己寫(xiě)一個(gè)新的輸出流

            了解了OutputStream及其子類(lèi)的結(jié)構(gòu)原理后,我們可以寫(xiě)一個(gè)新的輸出流,來(lái)添加新的功能。這部分中將給出一個(gè)新的輸出流的例子,它將過(guò)濾待輸出語(yǔ)句中的空格符號(hào)。比如需要輸出"java io OutputStream",則過(guò)濾后的輸出為"javaioOutputStream"。以下為SkipSpaceOutputStream類(lèi)的代碼:

            以下是代碼片段:
          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繼承,并且重寫(xiě)了它的write(int b)方法。在write(int b)方法中首先對(duì)輸入字符進(jìn)行了檢查,如果不是空格,則輸出。

            以下是一個(gè)測(cè)試程序:

            以下是代碼片段:
          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í)行以上測(cè)試程序,將要求用戶(hù)在console窗口中輸入信息,程序?qū)⑦^(guò)濾掉信息中的空格,并將最后的結(jié)果輸出到console窗口。比如:

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

            總 結(jié)

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

          posted on 2006-03-16 22:59 Web 2.0 技術(shù)資源 閱讀(283) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): 設(shè)計(jì)模式
          主站蜘蛛池模板: 桃园市| 德化县| 富川| 读书| 依安县| 威远县| 西平县| 塔城市| 鸡东县| 铅山县| 浑源县| 抚松县| 阿克陶县| 寿阳县| 搜索| 荥阳市| 河北省| 宁都县| 霍林郭勒市| 平乡县| 宜黄县| 荃湾区| 河池市| 财经| 乌拉特中旗| 阿拉尔市| 北安市| 新野县| 浦北县| 梓潼县| 柞水县| 遵化市| 游戏| 西和县| 奎屯市| 陇南市| 达州市| 天等县| 溧水县| 彭水| 高要市|