裝飾者模式:
動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。
下面咱們以星巴茲咖啡爲例:
咱們都知道星巴茲是以擴張速度最快而聞名的咖啡連鎖店,若是你在街角看到它的店,在對面街上確定還會看到另外一家。
由於擴張速度實在太快了,他們準備更新訂單系統,以合乎他們的飲料供應要求。
他們原先的類設計是這樣的。。。。。
定義一個名爲Beverage的抽象類,店內所提供的飲料都必須繼承自此類。該類中定義了一個名爲description(敘述)的實例變量,由每一個子類設置,用來描述作飲料 ,例如「超憂深焙(Daik Roast)咖啡豆」。還有一個cost()方法是抽象的,子類必須定義。本身的實現,此是子類返回飲料的價錢,同時還有一個getDescription()方法返回此敘述。
購買咖啡時,也能夠要求在其中加入各類調料例如:蒸奶,豆漿,魔卡或覆蓋奶泡。星巴茲會根據所加入的調料收取不一樣的收費的費用。
可是因爲有不少種飲料,你這所每種調味料都要繼承Beverage類的話,那麼就要「類爆炸」了。
這時,咱們應該用到
裝飾者模式。
設計原則:開放-關閉原則
開放-關閉原則:類應該對擴展開放,對修改關閉。
咱們的目標是容許類容易擴展,在不修改現有代碼的狀況下,就可搭配新的行爲。如能實現這樣的目標,有什麼好處呢?這樣的設計具備彈性能夠應對改變,能夠接受新的功能來應對改變的需求。
下面咱們來認識裝飾者模式,以一杯咖啡爲例,若是顧客想要一杯摩卡和奶泡深焙咖啡,那麼,要作的是:
1.拿一個深焙咖啡(DarkRoast)對象
2.以摩卡(Mocha)對象裝飾它
3.以奶泡(Whip)對象裝飾它
4.調用cost()方法,並依賴委託(delegate)將調料的價錢加上去
前面咱們說過的
DarkRoast對象繼承Beverage,下面咱們定義Beverage對象
public abstract class Beverage{
String description="Unknown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
下面咱們看看DarkRoast對象
public class DarkRoast extends Beverage{
public DarkRoast(){
description="DarkRoast";
}
public double cost(){
return 1.99;
}
}
爲了達到類的 匹配,咱們的調料(Condiment)也應該繼承Beverage
public abstract class Condiment extends Beverage{
public abstract String getDescription();//全部的 裝飾者都必須從新實現
}
下面咱們即可以定義摩卡(Mocha)和奶泡(Whip)對象來裝飾深焙(DarkRoast)咖啡了
public class Mocha extends Condiment{
Beverage beverage;//用一個實際變量記錄飲料,也便是被裝飾者
public Mocha(Beverage beverage){
this.beverage=beverage;
}
public String getDescription(){
return beverage.getDescription+",Mocha";
//咱們但願敘述不僅是描述飲料("DarkRoast"),而是完整地連調料都描述出來("DarkRoast,Mocha")因此首先利用委託的作法,獲得一個敘述,而後在其加上附加的敘述(例如 "Mocha")
}
public double cost(){
return 0.20+beverage.cost;//要計算帶Mocha飲料的價錢。首先把調用委託給裝飾對象,以計算價錢,而後加上Mocha的價錢,獲得最好的結果。
}
}
奶泡(Whip)對象也一樣的道理。
如今咱們即可以享受裝飾者模式帶來的方便了。
public class StartbuzzCoffe{
public static void main(String[] args){
Beverage beverage=new DarkRoast();
System.out.println(beverage.getDescription()+" $"+beverage.cost());
beverage=new Mocha(beverage);
System.out.println(beverage.getDescription()+" $"+beverage.cost());
}
}
到如今,裝飾者模式基本瞭解了,下面總結一下:
1.繼承屬於擴展形式之一,但不見得是達到彈性設計的最佳方式
2.在咱們設計中,應該容許行爲能夠被擴展,而無須修改現有的代碼
3.組合和委託可用於 在運動時動態地加上新的行爲
4.除了繼承,裝飾者模式也可讓咱們擴展行爲
5.裝飾者模式意味着一羣裝飾者類,這些類用來包裝具體組件
6.裝飾者類反映出被裝飾的組件類型(事實上,他們具備相同的類型,都通過接口或繼承實現)
7.裝飾者能夠在被裝飾者的行爲前面與/或後面加上本身的,甚至將被裝飾者的行爲整個取代掉,而達到特定的目的
8.你能夠使用無數個裝飾者包裝一個組件
9.裝飾者通常對組件的客戶是透明的,除非客戶程序依依賴於組件的具體類型
10.裝飾者會致使設計中出現許多小的對象,若是過分使用,會讓程序變得複雜