父博文位址:設計模式 - Design Patterns
一、是什麼
-
問題
使用繼承是靜态的擴充:
- 随着系統功能增多造成了類數量指數級增加。
- 且基類的功能并不适用于所有子類。
-
尋找一個設計模式原則
開閉原則:類應該對擴充開放,對修改關閉。換句話說:在不修改類的前提下擴充類。
-
裝飾者模式定義
動态的将責任附加到對象 上。若要擴充功能,裝飾者提供了比繼承更有彈性的替代方案。
類圖如下:
二、問答
-
及其子類依然繼承自AbstractDecorator
AbstractComponent
不是嗎?
我們依然使用了繼承,的确如此。不過這麼做的重點在于,裝飾者和被裝飾者需要是同一個類型,這很關鍵。我們隻是利用繼承達到“類型比對”,而不是利用繼承擷取“行為”。
-
加入行為
我們不是通過繼承來“加入新行為”,而是通過“組合”。
-
為什麼裝飾者是抽象類?
通常使用抽象類,當然Java 中也可以使用接口,此時需要把構造函數定義在各個裝飾者子類中。
三、執行個體
1. FilterInputStream
是 InputStream
的裝飾器
FilterInputStream
InputStream
類圖如下:
- 介紹
是抽象被裝飾類,InputStream
,ObjectInputStream
,FileInputStream
等是可以被裝飾的具體元件。ByteArrayInputStream
是裝飾者類(這裡沒有設計為抽象),FilterInputStream
,BufferedInputStream
,LineNumberInputSream
等是具體的裝飾者類。DataInputSream
-
代碼FilterInputStream
可以看到,包裝類隻有一個有參數的構造函數,參數是被包裝類。包裝類可以動态的添加功能,這裡覆寫了public class FilterInputStream extends InputStream { protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } public int read() throws IOException { return in.read(); } // others }
并簡單的調用被包裝類的同名方法。read()
- 一個可能的用例
被FileInputSream
裝飾,BufferedInputSream
又被BufferedInputSream
裝飾。LineNumberInputSream