問題描述
.他們的咖啡有不同的品牌,有latte(拿鐵),卡布奇諾(cappuccino)等等當然以後肯定會改變,同時各種咖啡都可以加上milk(牛奶),soy(豆漿),sugar(糖)等配料,當然配料也會改變(一杯咖啡可以加兩分牛奶).還有咖啡有大杯小杯.
版本一
一個coffee父類,各種品牌的開發繼承之. 語言是蒼白的 看代碼!
public class Coffee {
private String description; //品牌描述
private String size;
private int milk;
private int sugar;
public Coffee(){ //構造函數
description="unknow coffee";
size="small";
}
public Coffee(int milk,int sugar,String size,String brand){
this.milk=milk;
this.sugar=sugar;
this.size=size;
description=brand;
}
public String getDescription(){
return description+" "+size+"杯咖啡 milk:"+milk+"份 sugar:"+sugar+"份";
}
public double cost(){
if(size.equals("small")) //小杯大杯分開
return milk*1.1+sugar*1.2;
if(size.equals("jourm"))
return milk*1.2+sugar*1.4;
return 0;
}
}
然後就是一個拿鐵(iatte)繼承了coffee 别的品牌都一樣的
public class iatte1 extends Coffee{
public double cost(){
return super.cost()+2.5;
}
public iatte1(int milk,int sugar,String size) {
super(milk, sugar, size, "iatte");
}
}
再看測試類
import condiment.*;
import base.Beverage;
import brand.*;
public class test {
public static void main(String[] args){
Coffee aCoffee=new iatte1(2,3,"small");
System.out.println(aCoffee.getDescription());
System.out.println(aCoffee.cost());
}
}
測試結果
iatte small杯咖啡 milk:2份 sugar:3份
8.3
大家可以看出來 關鍵的cost()計算和getdescription 都是在父類中完成的.
這樣看起來還不錯 不過真的不錯嗎?
幾個問題
1:一旦我要更改某一種調料的價格怎麼辦?
2:我要新增一種調料怎麼辦?
3:如果有了新的飲料,如茶,問題是茶不會加奶呀 怎麼辦?
分析這個三個問題
其中1,2違反了開閉原則.第三個的設計也不合适
.
此時我們看看 裝飾模式是怎麼解決這個問題的.
裝飾模式版本
我們建立一個抽象類beverage.
package base;
public abstract class Beverage {
public String description="unknow coffee";
public String size="unknow size";
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public abstract double cost();
}
讓所有的咖啡品牌都繼承beverage.
package brand;
import base.Beverage;
public class latte extends Beverage{
public double cost() {
if(size.endsWith("jorum"))
return 1.5;
else if(size.endsWith("small"))
return 1.2;
return 1.2;
}
public latte(){
size="jorum";
description="latte jorum coffee";
}
public latte(String size2){
size=size2;
description="latte "+size+" coffee";
}
}
其他品牌類似,不在贅述.
再建立一個所有調料(milk.soy等等)的基類condiment,并讓它繼承beverage.
package condiment;
import base.Beverage;
public abstract class condiment extends Beverage {
public abstract String getDescription();
}
然後所有的配料繼承condiment.
package condiment;
import base.Beverage;
public class sugar extends condiment {
Beverage beverage;
public sugar(Beverage beverage2){
beverage=beverage2;
}
public String getDescription() {
System.out.print("suga 的形容 \n");
return beverage.getDescription()+" ,sogar";
}
public double cost() {
return beverage.cost()+2.4;
}
}
其他配料如milk等似,不在贅述.
uml圖如下(取自head first design pattern )
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cGcq5SNxMDO4QmZhVGO1MWMxUmZyYzXxQzNxgTM4EzLchDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.jpg)
看看測試類.
import condiment.*;
import base.Beverage;
import brand.*;
public class test {
public static void main(String[] args){
System.out.println("第一杯");
Beverage aBeverage=new latte();
System.out.println(aBeverage.getDescription());
System.out.println(aBeverage.cost());
System.out.println();
System.out.println("第二杯");
Beverage bBeverage=new cappuccino("small");
bBeverage=new milk(bBeverage);
bBeverage=new milk(bBeverage);
bBeverage=new sugar(bBeverage);
System.out.println(bBeverage.getDescription());
System.out.println(bBeverage.cost());
}
}
大家看看,在第二杯的時候,我們給咖啡加糖,加牛奶就new一個牛奶,new一個糖然後加進去很形象不是嗎?
測試結果
第一杯
latte jorum coffee
1.5
第二杯
suga 的形容
milk 的形容
milk 的形容
cappuccino small coffee,milk,milk ,sogar
6.1
這裡有一個問題,這個小杯的含兩份牛奶一份糖的cappuccino的價格到底是怎麼算出來的呢?
public double cost() {
return beverage.cost()+2.4;
}
這是糖的cost 。
看咱們的測試代碼。Cappuccino最“外邊”包的是糖,當我們調用bBeverage.cost()的時候,其實就是用糖的cost。Ok,看上面糖的cost,2.4+beverage.cout()這句代碼裡的beverage指的是誰呢?
bBeverage=new milk(bBeverage);
bBeverage=new milk(bBeverage);
bBeverage=new sugar(bBeverage);
很顯然是牛奶。是以再調用牛奶的cost!繼續往上走,是以的問題都解決了。其實我建議朋友們再看這部分的時候最好開啟debug模式。親自一步一步調試一下就解決問題了。
下圖來自head first 裡面的咖啡例子
whip,mocha都是配料和本例子中的sugar.milk是一回事.darkroast是咖啡的品牌 相當于本例中的卡布奇諾,拿鐵.
在javaio中的應用
參考資料
<Head First Design Pattern>>