通過閱讀本篇文章,可以給喜歡使用繼承的開發人員提供一種新的思路。我們將會了解濫用繼承帶來的不良後果,同時也會介紹比繼承更合理的實現方式。
利用繼承設計子類的行為,是在編譯時期靜態決定的,而且所有的子類都會繼承到相同的行為。然而,如果能夠利用組合的做法擴充套件物件的行為,就可以在執行時動態地進行擴充套件。
假設現在有一家知名的咖啡店,因為擴充套件速度太快,希望你能幫他們重新設計一套飲料銷售系統,滿足當下的需求。
原先的類設計結構圖如2-1所示
顧客在購買飲料時,通常會加入各種各樣的調料,比如牛奶、mocha,豆漿(soy)。所以飲料系統需要考慮調料的問題。我們第一次嘗試,如果調料不同就新定義乙個新的飲料物件。設計結構圖如圖2-2所示
從圖中我們可以看下,這種設計方式雖然可以實現功能,但是物件太多,如果新加了一種調料,有需要建立很多的飲料物件,而且原有的**邏輯也需要更改。
能不能解決飲料物件太多的問題呢?利用繼承和例項變數,把所有的調料都定義在超類中,並給這些調料設定屬性。如果子類需要調料,那就給調料設定相應的屬性。對應的結構圖如圖2-3所示
利用這種方法,雖然可以減少類的數量,但是所有的子類,都會繼承基類中的調料,假設有些飲料不需要牛奶作為調料,但是飲料物件中仍然會有牛奶調料屬性,這顯然有點不太合理。
通過上文,我們已經認識到利用繼承無法完全解決飲料系統對應的問題,比如:類數量太多,設計死板,基類的屬性和方法並不適用於所有的子類。
我們以飲料為主體,然後在執行時以調料來」裝飾「飲料。比方說如果顧客想要摩卡和奶泡深焙咖啡,那麼要做的是:
1、那乙個深焙咖啡(darkroast)物件
2、以摩卡(mocha)物件裝飾它;
3、以奶泡(whip)物件裝飾它;
4、呼叫cost()方法,並依賴委託(delegate)將調料的價錢加上去。
如何通過**實現這種美妙的思想,我們首先來了解裝飾者的定義和類圖。
裝飾者模式動態地將責任附加到物件上。若要擴充套件功能,裝飾者提供了比繼承更有彈性的替代解決方案。
類結構圖如2-4所示
我們利用裝飾者模式,重新改造飲料系統的結構。如圖2-5所示
**實現
package cn.lzz.hf.third;
public abstract class beverage
protected void setamount(double amount)
protected double getprice()
protected void setprice(double price)
public string getdescription()
public void setdescription(string description)
}
package cn.lzz.hf.third;
public class darkroast extends beverage
public darkroast(double amount,double price,string description)
@override
public string getdescriptions()
@override
public double cost()
}
package cn.lzz.hf.third;
/** * 調味品裝飾超類
* @author administrator
* */
public abstract class condimentdecorator extends beverage
public condimentdecorator(beverage beverage)
@override
public string getdescriptions()
return decriiption.tostring();
} @override
public double cost()
protected beverage getbeverage()
protected void setbeverage(beverage beverage)
}
package cn.lzz.hf.third;
public class milk extends condimentdecorator
public milk(double amount,double price,string description,beverage beverage)
}
package cn.lzz.hf.third;
public class mocha extends condimentdecorator
public mocha(double amount,double price,string description,beverage beverage)
}
package cn.lzz.hf.third;
public class soy extends condimentdecorator
public soy(double amount,double price,string description,beverage beverage)
}
package cn.lzz.hf.third;
public class whip extends condimentdecorator
public whip(double amount,double price,string description,beverage beverage)
}
package cn.lzz.hf.third;
public class test
}
執行結果
description:泡沫,大豆,摩卡,牛奶,焦炒咖啡
totalprice:17.1
裝飾者模式意味著一群裝飾者類,這些類用來包裝具體元件。裝飾者可以在被裝飾者的行為前後加上自定義的行為,甚至可以將被裝飾者的行為整個取代掉,而達到特定的目的。當然,裝飾者模式會導致設計中出現許多小物件,如果過度使用,會讓程式變得很複雜。
詳細內容可以參考《head first 設計模式》。
大話設計模式之裝飾者模式
現在有乙個需求 設計乙個qq秀,可以隨意搭配服飾。直接將上 父類的父類person 為什麼需要父類的父類 乍看父父類其實是可有可無的,但如果刪掉,你會發現父類finery的decorate無法放裝飾者 package decoratorpattern public class person priv...
大話設計模式之裝飾者模式
裝飾者模式通過使用繼承,能夠將物件一層一層地包裝起來。1,person是被裝飾的物件,裝飾者模式的類圖中,所有的類都繼承自person類。person類有乙個show方法,用來展示person物件哪些服飾裝飾了。通過繼承,所有的類都有show方法,因此當人穿上了某種服飾之後,就可能呼叫該服飾的sho...
大話設計模式 裝飾者模式(總結)
1 裝飾者模式的一般應用場景 當系統增加新的功能,需要給類增加新的功能,而這些新的功能又主要是為了修飾原來類中的核心職責或者功能,也就是說,這些新的功能是用來修飾的,而且這些用來修飾的功能是在滿足某乙個特定情境下才會有需要執行的,這個時候就需要用到 裝飾者模式。2 裝飾者模式的構成 1 抽象構件 c...