http://oreilly.com/catalog/hfdesignpat/chapter/ch03.pdf
Java I/O 正是 real world decorator pattern 的例子。
decorator pattern 常被抱怨因為子類別太多難以看懂,
不過這件事通常要靠學習 decorator pattern 來解決。
請看第 24 頁(或頁碼101),
decorator pattern 有 4 類基本的角色
1. 抽象的元件,用來定義基本行為
2. 實體元件,能直接使用的元件。
3. 抽象的裝飾者,定義裝飾者基本行為
4. 實體裝傭者,實作裝飾者行為。
InputStream 就是 [1] 抽象元件。
它定義所有 InputStream 衍生類別應用的共通行為。
而 FileInputStream、StringBufferInputStream、ByteArrayInputStream 等
都是能直接使用的元件[2]。
所謂「能直接」使用的意義是:
1. 它是最初的元件狀態來源,
FileInputStream 的 Input 需來自 File
建構子需為 File 物件或 FileDescriptor 或檔案路徑
StringBufferInputStream 的 Input 需來自 String
建構子只能是字串
ByteArrayInputStream 的 Input 需來自 byte[]
建構子需為 byte[] 或 byte[] 區段
2. 它的實作不能透過裝飾而來,因為沒有狀態的本體,裝飾沒有意義。
先掌握非裝飾用的元件,再來看裝飾者的基本行為:
http://java.sun.com/j2se/1.4.2/docs/api/java/io/FilterInputStream.html
它有唯一的建構子 InputStream。
這說明它的風格是透過建構的過程,實現裝飾的效果。
因此,下面這樣的用法是相當常見的:
new LineNumberInputStream(
new BufferedInputStream(
new FileInputStream("foo.txt")
)
);
FileInputStream 是實體元件負責提供狀態的來源,
BufferedInputStream 裝飾 FileInputStream 提供讀檔時的 buffer
因為 read() 方法只會讀出適當的筆數,這樣做沒什麼效率。
透過 BufferedInputStream 預先讀出一「塊」資料,放在 buffer 內
read() 不會頻繁地讀寫硬碟,而是在 buffer 內的資料沒有時,
才會有實際的讀取作用。
LineNumberInputStream 提供行號的管理,
我想應該就是在 read() 要吐出資料前判斷是否有經過換行字元吧。
當我們認識 decorator pattern 並理解 Java IO 是這樣設計。
那麼面對再多的 subclass 就無需畏懼了。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.231.55.86
剛好 First Head Design Pattern 的 ch3 有試閱 :D