每天一個設計模式之裝飾者模式
阿新 • • 發佈:2019-01-29
什麼是“裝飾者模式”
裝飾者模式:裝飾者模式可以動態地將責任附加到物件上。若要拓展功能,裝飾者模式提供了比繼承更有彈性的替代方案。
在面向物件設計過程中,我們可以遵循一個原則:開閉原則(對拓展開放,對修改關閉)
而裝飾者模式就很好的遵循了這個原則,在對類進行拓展的時候可以不修改程式碼,以便搭配新的行為。這種設計更具有彈性,可以更好地應對改變和接收新的需求。
為什麼要用“裝飾者模式”
我們舉個簡單的例子:
我們需要設計一個咖啡訂單系統,我們很容易就可以想到,新建一個抽象類Beverage,
/**
* 咖啡的介面
* */
public abstract class Beverage {
String description = "這只是個咖啡,我也不知道是什麼咖啡";
public String getDescription() {
return description;
}
public abstract double cost();
}
然後通過子類繼承Beverage並實現抽象方法cost(),得到不同的價格。
那麼問題來了: 如果我要在咖啡中新增各種調料,例如:蒸奶、豆漿、摩卡、奶泡等等。 新增不同的調料收取的價格不同,我們該怎麼辦?有些人會想到,根據不同的搭配組合實現不同的類,那麼這個想法會發生什麼事情呢?沒錯。。。類爆炸!
如何使用裝飾者模式
那麼這個時候,裝飾者模式就可以上場了:
我們首先來看看裝飾者模式的類圖
組成
- Component 抽象構件 :一個抽象類或者一個介面
- ComcreateComponent 具體構件:抽象類或者介面的實現,我們要裝飾的就是它(咖啡)
- Decorator 裝飾角色: 一個抽象類或者一個介面,裡面必然有一個指向Component 抽象構件的屬性
- 具體裝飾角色:裝飾用的具體角色,實現或繼承了Decorator 裝飾角色
實現
瞭解了具體的組成角色,那麼我們就可以實現一下了
首先,根據類圖我們需要準備一個Component 抽象構件,其實我們在文章開始就已經準備好了:
/**
* 咖啡的介面
* */
public abstract class Beverage {
String description = "這只是個咖啡,我也不知道是什麼咖啡";
public String getDescription() {
return description;
}
public abstract double cost();
}
接下來,我們準備一個ComcreateComponent 具體構件,也就是需要被我們裝飾的物件(這裡是咖啡)
/**
* 通過繼承Beverage抽象類,可以根據不同的咖啡定義不同的價格
* */
public class Espresso extends Beverage {
public Espresso() {
super.description = "濃縮咖啡";
}
@Override
public double cost() {
return 18.8;
}
}
然後,我們準備一個Decorator 裝飾角色,
**
* Decorator 裝飾角色, 繼承Beverage就可以對它的價格進行修改
* */
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
最後,我們實現一個這個Decorator 裝飾角色抽象類,使它變成具體的裝飾角色
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
//新增上摩卡
@Override
public String getDescription() {
return beverage.getDescription() + ", 摩卡";
}
//將價格改變為新增摩卡後的價格
@Override
public double cost() {
return beverage.cost() + 2.0;
}
}
/*=======================================================*/
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 奶泡";
}
@Override
public double cost() {
return beverage.cost() + 1.0;
}
}
//其實我們可以多實現幾種調料,這樣可能會吸引更多顧客呢
完成之後,我們測試一下被我們裝飾後的咖啡長什麼樣:
public class StarbuzzCoffee {
public static void main(String[] args){
Beverage beverage = new Espresso();
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.getDescription() + " ¥" + beverage.cost());
}
輸出結果:
濃縮咖啡, 摩卡, 奶泡 ¥21.8
從輸出結果看,我們確實根據調料改變了濃縮咖啡的價格,所以這就是裝飾者模式的好處。
那麼,總結來了
優點:
- 裝飾類和被裝飾類可以獨立發展,不會互相耦合。
- 裝飾者模式是繼承的一個替代方案。我們不管裝飾多少層,最終返回的還是該物件。
- 裝飾者模式可以動態拓展一個實現類的功能。
缺點:
- 裝飾層數過多的話,會導致除錯困難,系統複雜度提高。
應用場景:
- 需要動態地拓展某個類的功能或者新增一個附加功能。
- 需要為一批兄弟類新增功能或者改裝,首選裝飾者模式。
感謝閱讀本部落格。
需要聯絡請加QQ:352642663
歡迎聯絡我共同交流