模擬需求
更新一個(gè)訂單系統(tǒng),以滿足飲料供應(yīng)要求。
原先的設(shè)計(jì)是這樣的

圖片.png
每種飲料都需要實(shí)現(xiàn)cost抽象方法,來(lái)返回飲料的價(jià)錢。購(gòu)買咖啡時(shí)也可以要求在其中加入各種調(diào)料,商家會(huì)根據(jù)不同的調(diào)料收取不同的費(fèi)用。
如果這樣設(shè)計(jì):

圖片.png
這簡(jiǎn)直是“類爆炸”,基類中加入了新的功能并不適用于所有的子類,給維護(hù)造成了很大的困難,而且也不能應(yīng)對(duì)需求的變化。繼承是一種強(qiáng)耦合,在編譯時(shí)就動(dòng)態(tài)決定的,如果能夠利用組合的做法擴(kuò)展對(duì)象的行為,就可以在運(yùn)行時(shí)動(dòng)態(tài)地進(jìn)行擴(kuò)展。
類應(yīng)該對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。
定義裝飾者模式
裝飾者模式動(dòng)態(tài)地將責(zé)任附加到對(duì)象上,若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案。

圖片.png
裝飾飲料

圖片.png
不難發(fā)現(xiàn),裝飾者和被裝飾者都繼承了同一個(gè)抽象類。當(dāng)我們將裝飾者與組件組合時(shí),就是在加入新的行為,所得到的行為不是繼承于超類,而是由組合對(duì)象得來(lái)的。裝飾類繼承于抽象類,是為了有正確的類型,而不是繼承它的行為。
代碼實(shí)現(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)料必須重新實(shí)現(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(){
//要計(jì)算帶Mocha飲料的價(jià)錢,首先把調(diào)用方法委托給被裝飾對(duì)象計(jì)算,再加上Mocha的價(jià)錢
return 20 + beverage.cost;
}
}
//產(chǎn)生訂單
public static void main (String[] args){
//制造一個(gè)飲料
Beverage beverage = new darkRoast();
//用Mocha裝飾對(duì)象
beverage = new Mocha(beverage);
//用whip裝飾對(duì)象
beverage = new Whip(beverage);
system.out.println(beverage.getDescription()+"$"+beverage.cost());
}
jdk中的裝飾類:java/Io

圖片.png
BufferedInputStream和LineNumberInputStream都擴(kuò)展自FilterInputStream,而FileInputStream是一個(gè)抽象的裝飾類

圖片.png