從裝飾者模式的理解說JAVA的IO包

裝飾者模式的詳解
裝飾者模式動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性
的替代方案。
裝飾者模式設計類之間的關係:
裝飾模式類圖1
其中Component是一個超類,ConcreteComponen是被裝飾者,Decorator是裝飾者,裝飾者和被裝飾者有共同的超類Component,可是此時咱們發現Decorator和Component還有另一條線,這條線表示Decorator還要組合Component。
在我看來裝飾的模式中這幾個類的主要做用以下:
首先咱們看一個這樣的現象(這個是我在網上看到的例子,我把它引入進來主要是方便談談個人理解)
現象描述:
若是說繼承裏的超類是一個模具(Component),作出各類各樣的稍有不一樣的子類成品(ConcreteComponen,ConcreteDecoratorA,ConcreteDecoratorB)來知足各類各樣的功能。那麼把裝飾模式比做的一條生產線吧,一個產品(ConcreteComponen)傳過來,在各道工序不斷地給它加上新的功能,把它一步步按照順序包裝成一個全新的產品(Concrete DecoratorA,Concrete DecoratorB)。記住,這條生產線多是無限長的,這種包裝也能夠是無限添加的。
個人理解
1. Component是超類,他出現的意義是什麼呢?照理說Decorator直接去組合ConcreteComponent,就能夠去增強ConcreteComponent的行爲,成而加工出一個不通的子類成品。可是可能有這樣一種狀況,ConcreteComponent的平級的區域內還有ConcreteComponent1,ConcreteComponent2……這樣要爲每個ConcreteComponent都去寫一個Decorator嗎?這樣顯然不可能。因此抽象出Component的一個好處就是讓ConcreteComponent和Decorator彼此解耦。Decorator只要獲得Component對象的引用便可。
2. Decorator是裝飾者,而真正裝飾的過程是在Decorator的子類ConcreteDecoratorA和ConcreteDecoratorB中完成的,他們使用不一樣的裝飾方法,做出了不一樣的子類成品。Decorator的做用只是告訴你們,我要去裝飾ConcreteComponent,或許還會提供一些用這個裝飾者去裝飾的而造成的成品共用的特性和功能。
3. 裝飾者永遠是裝飾者,但裝飾者裝飾出來的成品也有可能會變成被裝飾者。即ConcreteDecoratorA和ConcreteDecoratorB有一天也會變到ConcreteComponen的地位。
只不過這個時候在ConcreteDecoratorA的旁邊可能會出現一個相似於Decorator的裝飾者DecoratorA,它一樣要繼承並組合超類Component。目的是相同的:解耦,讓一個裝飾者沒必要爲一個被裝飾者而存在
這時候的裝飾者模式的結構圖變成:
裝飾模式類圖2
由上圖說明一個道理,若是條件允許的話Decorator和DecoratorA的位置是能夠互相交換的。這就像衝一杯帶糖的奶粉,Decorator表示放糖,DecoratorA表示放奶粉,實際上是先放糖仍是先放奶粉,最終都能獲得ConcreteDecoratorAA(一杯帶糖的奶粉)。固然這是在條件允許的狀況下,在有些生產環境中,製作工序(裝飾的前後)是不能亂的。

裝飾者模式在JAVA IO中的應用
先給出Java IO包中主要類的關係:
java IO包中有四大等級結構InputStream,outputStream, InputStreamReader,outputStreamReader。InputStream和OutputStream處理8位字節流數據, Reader和Writer處理16位的字符流數據。InputStream和Reader處理輸入, OutputStream和Writer處理輸出。各個體系內部用到的都是裝飾者模式,而InputStream和InputStreamReader之間,outputStream和outputStreamReader之間用的是適配器模式
下面主要以InputStream和InputStreamReader爲例詳解
1. 從裝飾者模式看InputStream結構





InputStream的類圖關係
class java.lang.Object
|
|—class java.io.InputStream //輸入流,字節形式,爲如下的基類
| |
| |——ByteArrayInputStream //從字節數組中讀取
| |
| |——FileInputStream //從文件中讀取數據
| |
| |—— FilterInputStream //過濾流的基類,
| | | // 過濾能夠了解爲各類處理技術的形象稱呼
| | |
| | |——BufferedInputStream //緩衝技術,
| | | // 數據來自底層輸入流
| | |
| | |——DataInputStream //可讀java數據類型
| | |
| | |——PushbackInputStream //緩衝技術,
| | | // 數據來自任意輸入流
| | |
| | |——java.util.zip.GZIPInputStream
| | | //不是java.io包中的流。壓縮技術
| | |
| | |——java.security.DigestInputStream
| | | //不是java.io包中的流。處理流的摘要
| | |
| |—— .......
從圖中能夠看出,InputStream就是裝飾者模式中的超類(Component),ByteArrayInputStream,FileInputStream至關於被裝飾者(ConcreteComponent),這些類都提供了最基本的字節讀取功能。
而另一個和這兩個類是同一級的類FilterInputStream便是裝飾者(Decorator),BufferedInputStream,DataInputStream,PushbackInputStream…這些都是被裝飾者裝飾後造成的成品。
根據裝飾者模式的特色,咱們能夠總結出這些IO流的使用方法:
File file = new File ("hello.txt");
FileInputStream in=new FileInputStream(file);
BufferedInputStream inBuffered=new BufferedInputStream (in);
這裏BufferedInputStream主要是提供了緩存機制,先讀入一個byte[],等count到達緩存Byte[]的大小的時候,再一次讀入。
固然你也能夠寫成BufferedInputStream inBuffered =
new BufferedInputStream (new FileInputStream(new File ("hello.txt")));
從使用的角度來看裝飾者模式,能夠看出它的一個缺點:裝飾者模式的實現對於使用者是透明的,當使用者不熟悉你的實現的時,就很難理解。

同理你能夠學習一下另一個結構outputStream

2. 適配器模式看InputStreamReader
適配器模式比較簡單就很少講了,主要是解決了java沒法多繼承的問題,下面大概講一下IO包中是怎麼用這個模式的,用它來作什麼?
InputStreamReader和InputStream的功能的不一樣點在於InputStream是以二進制輸入 / 輸出, I/O 速度快且效率高,因爲讀到的是字節,也就不存在亂碼問題,平臺移植性好。可是它的 read ()方法讀到的是一個字節,很不利於人們閱讀。InputStreamReader類將字節轉換爲字符。 你能夠在構造器中指定編碼的方式,若是不指定的話將採用底層操做系統的默認編碼方式。
Java.io.Reader類提供了要求了繼承這個類的全部類必須提供
   /**
     * Reads characters into a portion of an array.  This method will block
     * until some input is available, an I/O error occurs, or the end of the
     * stream is reached.
     *
     * @param      cbuf  Destination buffer
     * @param      off   Offset at which to start storing characters
     * @param      len   Maximum number of characters to read
     *
     * @return     The number of characters read, or -1 if the end of the
     *             stream has been reached
     *
     * @exception  IOException  If an I/O error occurs
     */
abstract public int read(char cbuf[], int off, int len) throws IOException;
代碼註釋理解:讀出來的形式必須是字符,而不是字節了,InputStreamReader繼承於Reader,即具有了讀出字符的功能,而把什麼讀成字節的功能就要InputStreamReader去適配了,InputStreamReader的構造函數是這樣的:



    /**
     * Creates an InputStreamReader that uses the named charset.
     *
     * @param  in
     *         An InputStream
     *
     * @param  charsetName
     *         The name of a supported
     *         {@link java.nio.charset.Charset </code>charset<code>}
     *
     * @exception  UnsupportedEncodingException
     *             If the named charset is not supported
     */
    public InputStreamReader(InputStream in, String charsetName)
        throws UnsupportedEncodingException
    {
super(in);
if (charsetName == null)
    throw new NullPointerException("charsetName");
sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
    }
用的是InputStream去適配InputReader。

3. 淺談Reader體系
Reader體系中一樣用到的是裝飾者模式,可是有一點不一樣,Reader體系中的FilterRead類和InputStream體系中的FilterInputStream的功能不一樣,它再也不是裝飾者。
這一點能夠從BufferReader和BufferStreamReader的實現不一樣能夠看出
bufferReader:public class BufferedReader extends Reader
BufferedInputStream:public class BufferedInputStream extends FilterInputStream
但模式仍是相同的。在Reader我沒找到FilterInputStream相似做用的東西
下面看看Reader IO的使用方法
1. File file = new File ("hello.txt");  
2. FileInputStream in=new FileInputStream(file);
3. InputStreamReader inReader=new InputStreamReader(in);
4. BufferedReader bufReader=new BufferedReader(inReader);
能夠看出步驟2到3使用的是適配器模式,而3到4使用的是裝飾者模式

好了,以上就是我學習設計模式和java IO的心得,本身也是初學者,但願對一樣這塊不太瞭解的人有所幫助,有什麼意見你們能夠提出。java

相關文章
相關標籤/搜索