裝飾者模式與其在Java API中的運用
一、裝飾者模式簡介
裝飾者模式,是面向對象編程領域中,一種動態地往一個類中添加新的行為的設計模式。就功能而言,裝飾者模式相比生成子類更為靈活,這樣可以給某個對象而不是整個類添加一些功能。
1.基本原理
通過使用裝飾者模式,可以在運行時擴充一個類的功能。原理是:增加一個裝飾類包裹原來的類,包裹的方式一般是通過在將原來的對象作為修飾類的構造函數的參數。裝飾類實現新的功能,但是,在不需要用到新功能的地方,它可以直接調用原來的類中的方法。裝飾類必須和原來的類有相同的接口。
裝飾者模式是類繼承的另外一種選擇。類繼承在編譯時候增加行為,而裝飾者模式是在運行時增加行為。
當有幾個相互獨立的功能需要擴充時,這個區別就變得很重要。在有些面向對象的編程語言中,類不能在運行時被創建,通常在設計的時候也不能預測到有哪幾種功能組合。這就意味著要為每一種組合創建一個新類。相反,裝飾者模式是面向運行時候的對象實例的,這樣就可以在運行時根據需要進行組合。一個裝飾者模式的示例是JAVA里的 Java I/O Streams 的實現。
裝飾者模式的UML類圖:
2.示例代碼
以 砂鍋羊肉面 為實例,別問為什么,(╯°□°)╯︵┻━┻
Component相當于Marmite(砂鍋)類:
public abstract class Marmite {
String description = "砂鍋";
public String getDescription() {
return description;
}
public abstract Integer cost();
@Override
public String toString() {
return "這是一碗:" + getDescription() + ",價格:" + cost() + "元";
}
}</code></pre>
ConcreteComponent是NoddlesMarmite(砂鍋面條)類:
public class NoddlesMarmite extends Marmite {
public NoddlesMarmite() {
description = "砂鍋面條";
}
public Integer cost() {
return 8;
}
}</code></pre>
Decorator是MaterialDecorator
public abstract class MaterialDecorator extends Marmite {
public abstract String getDescription();
}
ConcreteDecorator是MuttonMarmite:
public class MuttonMarmite extends MaterialDecorator {
Marmite marmite;
public MuttonMarmite(Marmite marmite) {
this.marmite = marmite;
}
@Override
public String getDescription() {
return "羊肉、" + marmite.getDescription();
}
@Override
public Integer cost() {
return 5 + marmite.cost();
}
}</code></pre>
這是測試代碼:
public class MarmiteTest {
public static void main(String[] args) {
Marmite marmiteNoddle = new NoddlesMarmite();
System.out.println(marmiteNoddle.toString());
Marmite muttonMarmiteNoddle = new MuttonMarmite(marmiteNoddle);
System.out.println(muttonMarmiteNoddle.toString());
}
}
二、Java API中裝飾者的運用
先看一段demo
public class JavaDemo {
public static void main(String[] args) {
System.out.println("請輸入一句話:");
BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in);
String msg = "wocao";
try {
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(bufferedInputStream));
msg = bufferedReader.readLine();
} catch (Exception e){
e.printStackTrace();
}
System.out.println("輸入的是:" + msg);
}
}
這段代碼的功能是將控制臺中輸入的內容打印出來。
查看 java api 得知
BufferedInputStream繼承的是FilterInputStream,如下圖:

FilterInputStream繼承的是InputStream,并且有InputStream對象的一個引用

由此可以得出
InputStream相當于Component,FileterInputStream相當于Decorator,BufferedInputStream相當于ConcreteDecorator,System.in相當于ConcreteComponent。
三、自己實現一個關于InputStream的ConcreteDecorator
talk is cheap, show me the code
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in){
super(in);
}
@Override
public int read() throws IOException {
int c=super.read();
return (c==-1?c:Character.toLowerCase((char)c));
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int result=super.read(b,off,len);
for(int i=off;i<off+result;i++){
b[i]=(byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}</code></pre>
不想解釋了,心累
看不懂的,送你一幅圖:

---------------------------------------EOF--------------------------------------
參考資料:
-
-
Head First設計模式
來自:https://segmentfault.com/a/1190000008305233