設計模式 --- 裝飾者模式 (The decorator pattern)
ok .. 我們繼續第二個模式 --- 裝飾者模式
我們繼續以前的書寫習慣,按照下面的順序。。
1. 什麼是裝飾者模式
還是按照書上的定義,裝飾者模式 --- 為一個對象動態添加額外的響應性。裝飾者模式可以為子類的擴充功能添加靈活的改變能力(The Decorator Pattern attaches additional reponsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.)。
這樣講,連我自己都覺得抽象。。呵呵。那我舉們個例子先。
(1)如果我們有第一種飲料 --- 咖啡,價格20塊。
(2)然後我們有第二種飲料 --- 加糖咖啡, 糖要5塊,所以總價格25塊。
那我們怎麼描述這兩種飲料的之間的關係呢?如果我們使用裝飾者來處理的話,我們可以這樣描述它們的關係:
我們定義一個飲料介面,然後首先咖啡類實現這個介面,然後它的價格方法返回20塊。
我們再定義加糖咖啡類,同樣實現飲料介面,因為它也是飲料。但是它封裝了咖啡類。然後它的價格方法,首先直接調用咖啡的價格,因為它封裝了咖啡嘛。然後再加上自己的價格就好了。
估計這樣講還是很迷惑,沒事。我們繼續往下分析。。。
2. 裝飾者模式的用途
根據上面的描述,那麼裝飾者就是在我們已經有一套既存的系統在啟動並執行時候,然後我們需要增強它的功能。就像我們本來賣咖啡,然後突然有天我們需要賣加糖的咖啡,我們就可以不用修改原來咖啡對象的代碼,直接裝飾原來的咖啡對象就好了。
3. 裝飾者模式的用法
ok ....... 講完裝飾者模式的定義和用途後,我們再詳細詳細講講到底怎麼用裝飾者。。
還是繼續上面例子,如果我們之前有一個系統裡面有個咖啡類,但是我們的boss打算推出一種新的飲料種類,好吸引顧客,也就是加糖的咖啡。
那我們這些程式員怎麼辦呢,老闆的吩咐我們肯定要做的。我們肯定是希望在不要修改原有代碼的基礎上,來添加新的功能。
我們可以分以下幾步完成:
(1) 首先我們來假定我們原來有個飲料介面:
public interface Drink{
public int getPrice();
}
然後我們的咖啡類也許是這樣實現的
public class Coffee implements Drink{
public int getPrice(){
return 20;
}
}
(2) ok ... 一切分析完畢,我們來添加新的飲料 --- 加糖咖啡
public class SugarCoffer implements Drink{
private Drink drink;
public SugarCoffer(){}
public SugarCoffer(Drink drink){
/// 這裡我們傳入咖啡對象
this.drink = drink;
}
public int getPrice(){
return ownPrice() + drink.getPrice();
}
private int ownPrice(){
return 5;
}
}
(3) 由於加糖咖啡也是實現了飲料介面,所以之前可以用咖啡對象的地方,我們都可以用加糖咖啡來代替。因為我們是面向介面編程,而不是物件導向編程。。。
如果有天我們的變態老闆哪天又要添加新的飲料,比如,要推出冰爽加糖咖啡,冰爽費是10塊。那麼應該是35塊錢。
我們可以這樣依葫蘆畫瓢。
public class IceSugarCoffer implements Drink{
private Drink drink;
public IceSugarCoffer(){}
public IceSugarCofffer(Drink drink){
///這裡我們可以傳入加糖咖啡對象
this.drink = drink;
}
public int getPrice(){
return ownPrice() + drink.getPrice();
}
private int ownPrice(){
return 10;
}
}
4. JDK 裡面的裝飾者例子
在JDK原始碼裡面,我們可以發現使用裝飾者模式的地方還是蠻多的,比如Java檔案讀寫類的實現就大量採用了裝飾者模式。
比如:
InputStream
FileInputStream StringBufferInputStream ByteArrayInputStream FilterInputStream
這裡下面行的類,比如FilterInputStream等等能就是裝飾InputStream, 它們共同的介面是Closeable。
就像FilterInputStream的構造方法是這樣實現的:
protected FilterInputStream(InputStream in) {
this.in = in;
}
很明顯,這裡FilterInputStream封裝了InputStream這個對象。
5. 最後總結裝飾者模式
裝飾者模式 --- 為你的子類裝飾眼睛(Desgin eye for the inheritance guy)。。 因為裝飾者模式可以動態隨時注入任何一個裝飾者到系統裡面(因為它們是實現了相同的介面)。它就像有眼睛的子類一樣,隨時找到最合適的裝飾者。 ////// ^^