該模式在java中比較典型的應用也就是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);
可以看到,用戶端使用是比較麻煩的,這就是裝飾模式的缺點。