裝飾模式(decorator)
裝飾模式以對客戶端透明的方式擴充套件物件的功能,是繼承關係的乙個替代方案。
裝飾模式通過建立乙個包裝物件,也就是裝飾,來包裹真實的物件。
裝飾模式以對客戶端透明的方式動態地給乙個物件附加上更多的責任。換言之,客戶端並不會覺得物件在裝飾前和裝飾後有什麼不同。
裝飾模式可以在不創造更多子類的情況下,將物件的功能加以擴充套件。
裝飾模式把客戶端的呼叫委派到被裝飾類。裝飾模式的關鍵在於這種擴充套件是完全透明的。
抽象構件角色(component):給出乙個抽象介面,以規範準備接收附加責任的物件。
具體構件角色(concrete component):定義將要接收附加責任的類。
裝飾角色(decorator):持有乙個構件(component)物件的引用,並定義乙個與抽象構件介面一致的介面。
具體裝飾角色(concrete decorator):負責給構件物件「貼上」附加的責任。
在io中,具體構件角色是節點流,裝飾角色是過濾流。
filterinputstream和filteroutputstream是裝飾角色,而其他派生自它們的類則是具體裝飾角色。
裝飾物件和真實物件有相同的介面。這樣客戶端物件就可以以和真實物件相同的方式和裝飾物件互動。
裝飾物件包含乙個真實物件的引用(reference)。
裝飾物件接收所有來自客戶端的請求,它把這些請求**給真實的物件。
裝飾物件可以在**這些請求之前或之後附加一些功能。
這樣就確保了在執行時,不用修改給定物件的結構就可以在外部增加附加的功能。
public inte***cecomponent
這是抽象構件角色,是乙個介面。具體構件角色實現這個介面:
public裝飾角色:class concretecomponent implements
component
}
public其中包含了構件角色的引用,方法呼叫中利用構件角色的方法。class decorator implements
component
@override
public
void
dosomething()
}
具體裝飾角色(兩個):
public使用測試:class concretedecorator1 extends
decorator
@override
public
void
dosomething()
private
void
doanotherthing() }
public
class concretedecorator2 extends
decorator
@override
public
void
dosomething()
private
void
doanotherthing()
}
public問題引入class
client
}
咖啡店的類設計:
乙個飲料基類,各種飲料類繼承這個基類,並且計算各自的價錢。
飲料中需要加入各種調料,考慮在基類中加入一些布林值變數代表是否加入各種調料,基類的cost()中的計算各種調料的價錢,子類覆蓋cost(),並且在其中呼叫超類的cost(),加上特定飲料的價錢,計算出子類特定飲料的價錢。
缺點:類數量**、基類加入的新功能並不適用於所有的子類、調料價錢的改變、新調料的出現都會要求改變現有**;有的子類並不適合某些調料等情況……
設計原則
類應該對擴充套件開放,對修改關閉。
我們的目標是允許類容易擴充套件,在不修改現有**的情況下,就可搭配新的行為。
如能實現這樣的目標,有什麼好處呢?這樣的設計具有彈性可以應對改變,可以接受新的功能來應對改變的需求。
要讓oo設計同時具備開放性和關閉性,不是一件容易的事,通常來說,沒有必要把設計的每個部分都這麼設計。
遵循開放-關閉原則,通常會引入新的抽象層次,增加**的複雜度。
我們需要把注意力集中在設計中最有可能改變的地方,然後應用開放-關閉原則。
用裝飾者模式解決問題
解決咖啡店飲料問題的方法:
以飲料為主體,然後在執行時以調料來「裝飾」飲料。
比如,顧客想要摩卡(mocha)和奶泡(whip)深焙咖啡(darkroast):
darkroast繼承自beverage,有乙個cost()方法。
第一步,以darkroast物件開始;
第二步,顧客想要摩卡,所以建立乙個mocha裝飾者物件,並用它將darkroast物件包裝(wrap)起來;
第三步,顧客想要奶泡,所以建立乙個whip裝飾者物件,並用它將mocha物件包起來;(mocha和whip也繼承自beverage,有乙個cost()方法);
最後,為顧客算錢,通過呼叫最外圈裝飾者(whip)的cost()就可以。whip()的cost()會先委託它裝飾的物件(mocha)計算出價錢,然後在加上奶泡的價錢。mocha的cost()也是類似。
裝飾者和被裝飾物件有相同的超型別。
可以用乙個或多個裝飾者包裝乙個物件。
因為裝飾者和被裝飾者具有相同的型別,所以任何需要原始物件的場合,可以用裝飾過的物件代替。
裝飾者可以在所委託被裝飾者的行為之前與/或之後,加上自己的行為,以達到特定的目的。
物件可以在任何時候被裝飾,所以可以在執行時動態地、不限量地用你喜歡的裝飾者來裝飾物件。
裝飾者模式的定義
裝飾者模式動態地將責任附加到物件上。若要擴充套件功能,裝飾者提供了比繼承更有彈性的替代方案。
裝飾者模式的實現
實現類圖如下:
裝飾者和被裝飾者具有共同的超類,利用繼承達到「型別匹配」,而不是利用繼承獲得「行為」;將裝飾者和被裝飾者組合時,加入新的行為。
解決本文中飲料的具體問題時,圖中component即為beverage(可以是抽象類或者介面),而concretecomponent為各種飲 料,decorator(抽象裝飾者)為調料的抽象類或介面,concretedecoratorx則為各種具體的調料。
因為使用物件組合,可以把飲料和調料更有彈性地加以混合與匹配。
**外部細節:
**中實現的時候,通過建構函式將被裝飾者傳入裝飾者中即可,如最後的呼叫形式如下:
beverage beverage = new即完成了兩層包裝,此時再呼叫beverage的cost()函式即可得到總價。darkroast();
beverage = new
mocha(beverage);
beverage = new whip(beverage);
裝飾者模式的缺點:在設計中加入大量的小類,如果過度使用,會讓程式變得複雜。
Java IO 裝飾者模式
裝飾模式以對客戶端透明的方式擴充套件物件的功能,是繼承關係的乙個替代方案。裝飾模式通過建立乙個包裝物件,也就是裝飾,來包裹真實的物件。裝飾模式以對客戶端透明的方式動態地給乙個物件附加上更多的責任。換言之,客戶端並不會覺得物件在裝飾前和裝飾後有什麼不同。裝飾模式可以在不創造更多子類的情況下,將物件的功...
java I O之裝飾者模式
裝飾者模式意圖 動態的給乙個物件新增額外的職責。decorator比生產子類靈活。多用組合,少用繼承。利用繼承設計子類的行為,是在編譯時靜態決定的,而且所有的子類都會繼承到相同的行為。然而,如果能夠利用組合的做法擴充套件物件的行為,就可以在執行時動態地進行擴充套件 類應設計的對擴充套件開放,對修改關...
設計模式2 裝飾者模式(java IO)
設計類 開放 關閉原則 要對擴充套件開放,對修改關閉。多用組合,少用繼承。高內聚低耦合 具體原因 當我們設計的類不能滿足我們的需求的時候,我們可能設計乙個類去繼承它,但是這樣就會使物件之間高度的耦合。此時,我們就可以考慮使用裝飾者模式 把物件嵌入我們要擴充套件功能的類中,呼叫他的方法,然後跟我們定義...