Hello,即將要寫的這篇文章,是對剛剛學習完的裝飾者模式的一個總結啦,也不是什麼技術難點,就是鞏固一下啦。
一.裝飾者模式的定義
裝飾者模式動態的將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。
只看定義真的有些不明白,先簡單說明一下,下面還有例子呢。
(1)定義中提到了繼承,看來裝飾者模式是來解決擴展功能時使用繼承的不足的;
(2)可以做到運行時裝飾類,給對象賦予新的職責。
(3)還是看下面的例子吧。
二.實例--飲品店
飲品店裏有,飲品--咖啡、果汁、茶類,飲品中可以加不同的配料--摩卡、牛奶、糖、奶泡;不同的飲品加上不同的配料有不同的價錢,怎樣實現呢?
方式一:單純的繼承
最突出的缺點--造成類爆炸(組合的種類太多);
方式二:使用裝飾者模式
1.裝飾者模式的組成:抽象組件(Beverage)、具體組件(Coffee、Tea等)、抽象裝飾者(IngredientDecorator)、具體裝飾者(Mocha、Milk等),以例子說明的關係圖如下:
2.代碼示例:
抽象組件--超類--Beverage:
public abstract class Beverage { //description實例變量表示不同的描述,由子類賦值使用 String description = "Uknown Beverage"; public String getDescription() { return description; } //抽象方法,由子類實現 public abstract double cost(); }
具體組件--B_Coffee、B_FruitJuice等:
public class B_Coffee extends Beverage{ /** * 在構造器中設置飲料的描述 */ public B_Coffee(){ description = Description.COFFEE; } /** * 實現父類--抽象組件中的抽象方法 * 計算該飲料的價錢 */ public double cost() { return Cost.COFFEE; } }
public class B_FruitJuice extends Beverage{ public B_FruitJuice(){ description = Description.FRUIT_JUICE; } public double cost() { return Cost.FRUIT_JUICE; } }
抽象裝飾者--IngredientDecorator:
/** * 繼承的目的是爲了IngredientDecorator能夠取代Beverage * @author wangzhaoli * */ public abstract class IngredientDecorator extends Beverage{ /** * IngredientDecorator中覆蓋父類中的getDescription()方法 * 繼承IngredientDecorator的所有觀察者需各自實現 */ public abstract String getDescription(); }
具體裝飾者們--C_Mocha、C_Milk等:
/** * C_Mocha是一個裝飾者 * C_Mocha繼承的CondimentDecorator * CondimentDecorator繼承了Beverage * @author wangzhaoli * */ public class C_Mocha extends IngredientDecorator{ /** * 要讓C_Mocha能夠引用一個Beverage,做法是: * 1.用一個實例變量記錄Beverage,也就是被裝飾者; * 2.想辦法讓Beverage被記錄到實例變量中,即構造器參數實例化。 */ private Beverage beverage; public C_Mocha(Beverage beverage){ this.beverage = beverage; } /** * 實現父類CondimentDecorator中的抽象方法 */ public String getDescription() { //利用委託的方法得到之前的描述 return beverage.getDescription() + "," + Description.MOCHA; } /** * 實現父類的父類Beverage中的抽象方法 */ public double cost() { return beverage.cost() + Cost.MOCHA; } }
public class C_Milk extends IngredientDecorator{ private Beverage beverage; public C_Milk(Beverage beverage){ this.beverage = beverage; } public String getDescription() { return beverage.getDescription() + "," + Description.MILK; } public double cost() { return beverage.cost() + Cost.MILK; } }
測試類--main:
public class MainTest { public static void main(String[] args) { Beverage fruitJuice = new B_FruitJuice(); System.out.println(fruitJuice.getDescription()+":"+fruitJuice.cost()); System.out.println(); Beverage coffee = new B_Coffee(); coffee = new C_Mocha(new C_Mocha(new C_Suger(coffee))); System.out.println(coffee.getDescription()+":"+coffee.cost()); System.out.println(); Beverage tea = new B_Tea(); tea = new C_Mocha(tea); tea = new C_Milk(tea); tea = new C_Suger(tea); tea = new C_Form(tea); System.out.println(tea.getDescription()+":"+tea.cost()); System.out.println(); } }
測試結果:
Fruit Juice:8.0 Coffee,Suger,Mocha,Mocha:9.5 Tea,Mocha,Milk,Suger,Form:9.5
二.由實例說明裝飾者模式
1.裝飾者模式中很好的體現了組合(composition)和委託(delegation):
(1)利用繼承設計子類的行爲是在編譯時靜態決定的,利用組合的做法擴展對象的行爲可以在運 行時動態的進行擴展;
(2)利用繼承達到"類型匹配",而不是獲得"行爲",新的行爲是由"組合對象"得來的;
(3)利用組合和委託可以實現在運行時具有繼承的效果;
2.裝飾者模式完全遵循"開放--關閉原則":類應該對擴展開放,對修改關閉。
3.以例子說明裝飾者的使用:
拿一個咖啡對象,用摩卡裝飾它,再用牛奶裝飾它,然後調用cost()方法,並依賴委託 (delegate)將各種配料的價格加上去。
4.每個具體的組件都可以單獨使用,或者被裝飾者包裝起來動態的加上新行爲使用;
5.裝飾者與抽象組件是"有一個"的關係,所以需要在每一個具體裝飾者中定義一個實例變量以保存
某個具體組件的引用;
6.裝飾者的新行爲是指:通過在舊行爲前面/後面加上一些計算、拼接等處理;
7.裝飾者和被裝飾者對象有相同的超類型;
8.可以用一個或多個裝飾者包裝一個對象;
9.裝飾者可以所委託被裝飾者的行爲之前/之後,加上自己的行爲,以達到指定的目的;