歡迎大家的持續關註。上一次,我們結合第一篇推導出來的類圖,到第二篇根據類圖進行實際代碼的編寫,對裝飾者模式有了一個整體的概念以及實戰。不知道對你幫助如何呢?小編已經有門道了,看完接下來的一部分,你會恍然大悟,原來實際編碼中你一直在用裝飾者模式。 真實世界的裝飾者:Java I/O 看到標題,是不是就 ...
歡迎大家的持續關註。上一次,我們結合第一篇推導出來的類圖,到第二篇根據類圖進行實際代碼的編寫,對裝飾者模式有了一個整體的概念以及實戰。不知道對你幫助如何呢?小編已經有門道了,看完接下來的一部分,你會恍然大悟,原來實際編碼中你一直在用裝飾者模式。
真實世界的裝飾者:Java I/O
看到標題,是不是就很想往下看,到底是I/O中的什麼呢,讓你早已經擁有了裝飾者模式的實踐?就如書上給的描述,你第一次(還有第二次和第三次)看到這些API發出“哇”的驚嘆時,放心,你不是唯一收到驚嚇的人。下麵,我們馬上給出一個典型的對象集合,用裝飾這來將功能結合起來,以讀取文件數據:
裝飾 java.io 類
你發現了沒,java.io和之前的咖啡店其實沒有太大的差異。這裡使用了各種“輸入”流裝飾者來符合你的用途。
你會發現“輸出”流的設計方式也是一樣的。你還會發現Reader/Writer流和輸入流/輸出流的類相當類似。不過,出學過Java文件流的同學肯定知道,Java I/O也引出類裝飾者的一個“缺點”:利用裝飾者模式,常常造成設計中有大量的小類,數量實在太多,可能會造成使用此API程式員的困擾。不知道你之前有沒有搞暈過呢,小編初入Java I/O的世界的時候,很是暈頭轉向。
編寫自己的Java I/O 裝飾者
那麼,已經懂得了裝飾者的精髓,我們自己來編寫一個輸入的裝飾者如何呢?來一個小想法:編寫一個裝飾者,把輸入流內的所有大寫字元轉成小寫。趕緊行動吧。
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class LowerCaseInputStream extends FilterInputStream {
protected LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = in.read();
return (c == -1 ? c : Character.toLowerCase((char)c));
}
public int read(byte[] b,int offset,int len) throws IOException {
int result = in.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}
測試你的新Java I/O 裝飾者
基於上面的裝飾者,我們來實現下功能,看是否是符合你的需求呢?
public class InputTest {
public static void main(String[] args) throws IOException{
int c;
try {
// 設置FileInoutStream,先用BufferedInputStream裝飾它,再用我們嶄新的LowerCaseInputStream過濾器裝飾它
InputStream inputStream = new LowerCaseInputStream(
new BufferedInputStream(
new FileInputStream("test.txt")));
while ((c = inputStream.read()) >= 0) {
System.out.print((char)c);
}
inputStream.close();
} catch (IOException e) {
}
}
}
// 輸入內容:
I know the Decorator Pattern and HOW it's used in the JAVA.IO package.
// 運行結果
i know the decorator pattern and how it's used in the java.io package.
恭喜你,已經喜提裝飾者模式,在設計模式的世界里又更進一步了。這裡,我們通過咖啡廳賣升級訂單系統,來瞭解裝飾者模式一步步產生的過程;再通過實際的Java API中的I/O進一步鞏固他,並用自定義的I/O功能實現,來結束此次的裝飾者模式之旅,開不開心呢?
設計箱內的工具
還是按照之前的套路,總結下工具箱內新增的工具吧
OO基礎 本次沒有變化
抽象、封裝、繼承、多態
OO原則
封裝變化
多用組合,少用繼承
針對介面編程,不針對實現編程
為交互對象之間的松耦合設計而努力
對擴展開放,對修改關閉(現在有了開放-關閉原則引導我們。我們會努力的設計系統,好讓關閉的部分和新擴展的部分隔離)
OO模式
『策略模式』
『觀察者模式』
『裝飾者模式』動態地將責任附加到對象上。想要擴展功能,裝飾者提供有別於繼承的另一種選擇
遺留問題解答
哦,對了,上次還留下了一個新增的功能,在咖啡廳里顧客可以選擇小杯、中杯、大杯的需求,調料根據咖啡容量收費。例如:小中大杯的咖啡加上豆漿,分別加收0.10,、0.15、0.20。那怎麼做呢,請往下看。這裡僅列舉Soy類,其他類的代碼請移步到GitHub上查看。
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + " , Soy";
}
@Override
public double cost() {
double cost = beverage.cost();
if (beverage.getSize() == Size.TALL) {
cost += 0.10;
} else if (beverage.getSize() == Size.GRANDE) {
cost += 0.15;
} else if (beverage.getSize() == Size.VENTI) {
cost += 0.20;
}
return cost;
}
}
至此,我們又學完了一個設計模式,裝飾者模式。除了之前的要點之外,小編在這裡還得提醒下大家,裝飾者一般對組件的客戶是透明的,除非客戶程式依賴於組件的具體類型。你可以用無數個裝飾者包裝一個組件,但是這樣會導致設計中出現許多小對象,如果過度使用,會讓程式變得很複雜。所以,我們需要按需使用,而不是濫用噢。
已經陸陸續續學完了3個設計模式,不知道大家對這樣的方式有沒有不解,或者有沒有更多的建議,小編都會虛心接受。下次課程,我們學習工廠模式。
PS:代碼已經上傳,需要查看的朋友點擊此處HeadFirstDesign
推薦閱讀
愛生活,愛學習,愛感悟,愛挨踢