模擬需求
更新一個訂單系統(tǒng)偎肃,以滿足飲料供應(yīng)要求。
原先的設(shè)計是這樣的
圖片.png
每種飲料都需要實現(xiàn)cost抽象方法扮宠,來返回飲料的價錢抛虫。購買咖啡時也可以要求在其中加入各種調(diào)料松靡,商家會根據(jù)不同的調(diào)料收取不同的費用。
如果這樣設(shè)計:
圖片.png
這簡直是“類爆炸”建椰,基類中加入了新的功能并不適用于所有的子類雕欺,給維護(hù)造成了很大的困難,而且也不能應(yīng)對需求的變化棉姐。繼承是一種強(qiáng)耦合屠列,在編譯時就動態(tài)決定的,如果能夠利用組合的做法擴(kuò)展對象的行為伞矩,就可以在運行時動態(tài)地進(jìn)行擴(kuò)展笛洛。
類應(yīng)該對擴(kuò)展開放,對修改關(guān)閉乃坤。
定義裝飾者模式
裝飾者模式動態(tài)地將責(zé)任附加到對象上撞蜂,若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案侥袜。
圖片.png
裝飾飲料
圖片.png
不難發(fā)現(xiàn),裝飾者和被裝飾者都繼承了同一個抽象類溉贿。當(dāng)我們將裝飾者與組件組合時枫吧,就是在加入新的行為,所得到的行為不是繼承于超類宇色,而是由組合對象得來的九杂。裝飾類繼承于抽象類,是為了有正確的類型宣蠕,而不是繼承它的行為例隆。
代碼實現(xiàn)
public abstract class Beverage{
String description = "Unknow Beverage';
public String getDescription(){
return description;
}
public abstract double cost();
}
//Condiment(調(diào)料)裝飾抽象類
public abstract class CondimentDecorator extends Beverage{
//所有的調(diào)料必須重新實現(xiàn)getDescription方法
public abstract String getDescription();
}
//被裝飾者
public class Espresso extends Beverage{
public Espresso(){
description = "Espresso";
}
public double cost(){
return 1.99;
}
}
//具體裝飾類
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beveragge.getDescription() + ",Mocha";
}
pubic double cost(){
//要計算帶Mocha飲料的價錢,首先把調(diào)用方法委托給被裝飾對象計算抢蚀,再加上Mocha的價錢
return 20 + beverage.cost;
}
}
//產(chǎn)生訂單
public static void main (String[] args){
//制造一個飲料
Beverage beverage = new darkRoast();
//用Mocha裝飾對象
beverage = new Mocha(beverage);
//用whip裝飾對象
beverage = new Whip(beverage);
system.out.println(beverage.getDescription()+"$"+beverage.cost());
}
jdk中的裝飾類:java/Io
圖片.png
BufferedInputStream和LineNumberInputStream都擴(kuò)展自FilterInputStream,而FileInputStream是一個抽象的裝飾類
圖片.png