天天看點

設計模式-裝飾模式(Decorator)在jDK中IO系統的應用

    該模式在java中比較典型的應用也就是jdk的io系統了

    裝飾模式類圖

設計模式-裝飾模式(Decorator)在jDK中IO系統的應用

好吧,其實這類圖隻對UML熟悉的人才有用,裝飾模式有啥用?說白了就是在原來類的功能上,對這些功能做一些增強處理,當然為了增強功能而通過繼承也是一種有效的方式,當然對于各種組合比較多的情況下,使用繼承可能會有太多的類出現,是以就需要使用裝飾模式,當然裝飾模式的缺點也是顯而易見的,使用上會比較麻煩。

舉個例子:

   FileReader

   StringReader

   我要為這兩個類的read功能增加緩存功能,如果使用繼承方式,我需要兩個子類來完成,也許這兩個子類得叫BufferedFileReader和BufferedFileStringReader,如果要增加緩存功能的類有十個,那麼子類也就需要十個,但是如果用裝飾模式,我隻要增加一個裝飾類既可滿足,BufferedReader類,這個就是jdk1.1的io系統設計。

普通的裝飾模式簡單示例

//總接口

public interface Compoent {

public Object needGirl();

}

//執行類

public class GirlGet implements Compoent {

public Object needGirl() {

// TODO Auto-generated method stub

System.out.println("給你個素顔的女優美眉");

return null;

}

}

//裝飾類父類,可有可無

public abstract class Decorator implements Compoent {

public abstract Object needGirl();

}

//裝飾類

public class MakeUpDecorator {

private Compoent c = null;

public MakeUpDecorator(Compoent _c) {

this.c = _c;

}

public Object needGirl() {

// 女孩化妝

girlMarkUp();

return c.needGirl();

}

public void girlMarkUp() {

// 化妝

System.out.println("素顔的女優不好,化妝下!");

}

}

//用戶端

public class Client {

public static void main(String[] ben){

MakeUpDecorator mud = new MakeUpDecorator(new GirlGet());

mud.needGirl();

}

}

套用io模式的BufferedReader,StringReader,Reader的read功能來做說明:

首先來說明這三個類在上述類圖的位置:

Reader:Compoent也是Decorator的基礎類

StringReader:ConcreateComponent

BufferedReader:ConcreateDecoratorA

寫出簡略代碼,從jdk1.1中的源碼摳出來,去除了很多與該模式無關的代碼:

//Reader

public abstract class Reader implements Readable, Closeable {

abstract public int read(char cbuf[], int off, int len) throws IOException;

}

//StringReader

public class StringReader extends Reader {

public int read(char cbuf[], int off, int len) throws IOException {

int n = Math.min(length - next, len);

str.getChars(next, next + n, cbuf, off);

next += n;

return n;

}

}

//BufferedReader

public class BufferedReader extends Reader{

private Reader in = null;

cb = new char[sz];

public BufferedReader(Reader reader)[

in = reader;

}

public int read(char cbuf[], int off, int len) throws IOException

int n = read1(cbuf, off, len);

if (n <= 0)return n;

while ((n < len) && in.ready()) {

int n1 = read1(cbuf, off + n, len - n);

if (n1 <= 0)break;

n += n1;

}

return n;

}

private int read1(char[] cbuf, int off, int len) throws IOException {

if (nextChar >= nChars) {

//當讀取的長度超過緩存長度的時候,直接從in裡面讀取,也就失去了這個裝飾類的作用了。

if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {

return in.read(cbuf, off, len);

}

//如果讀取的下個字元索引超過了目前的緩存長度,也就是說不在緩存中,那麼重新加載下一組緩存.

fill();

}

//當加載緩存後發現,讀取的下個字元索引仍舊超過緩存長度,其實就是加載下一組失敗,也就是說已經讀取完畢了。

if (nextChar >= nChars)return -1;

int n = Math.min(len, nChars - nextChar);

//從緩存中讀取字元

System.arraycopy(cb, nextChar, cbuf, off, n);

nextChar += n;

return n;

}

private void fill() throws IOException {

//建立一個緩存,緩存的長度可設定,為設定是預設的

//首先從in中擷取指定長度的流到緩存中去。加速通路.

//核心語句就下面一句

n = in.read(cb, dst, cb.length - dst);

}

從上面可以看出,BufferedReader類其實就是将Reader的子類(ConcreateComponent)也就是這裡的StingReader的資料放入緩存,然後操作read方法的時候,從緩存中讀取,但是實際上的流還是通過StringReader來擷取的。也就是說BufferedReader對StringReader類的read功能增加了緩存功能,在事實上,你不使用BufferedReader也可以直接操作StringReader的read功能,隻是沒有了緩存效果而已。

用戶端使用的代碼:

String s = "This is the/n/ninternal StringReader buffer./ndderwe"; 

StringReader stringReader = new StringReader(s); 

BufferedReader bufReader = new BufferedReader(stringReader); 

可以看到,用戶端使用是比較麻煩的,這就是裝飾模式的缺點。

繼續閱讀