設計模式之裝飾者模式(二)

Dimple91發表於2019-04-08

歡迎大家的不嫌棄,繼續和我一起學習設計模式。上一篇已經把裝飾者模式的類圖有了一個整體的出來,末尾說的去想想實現的程式碼,你實踐了嗎?是什麼原因讓你實踐了呢?又是什麼原因讓你沒有動手呢?沒動手,可能是思路還不夠明確是嗎?

接下來,我們繼續學習。通過程式碼實現的方式,來搞定裝飾者模式。

寫下程式碼

動手的時候來啦,我們先從Beverage類下手。這不需要修改原有的設計,如下所示:

/**
 * 
 * @Description: Beverage是一個抽象類,有兩個方法:getDescription()以及cost()
 * @author:XuYue
 */
public abstract class Beverage {
	String description = "Unknown Beverage";
	
	// getDescription()已經在此實現了,但是cost()必須在子類中實現
	public String getDescription() {
		return description;
	}
	
	public abstract double cost();
}
複製程式碼

然後我們繼續實現Condiment(調料)抽象類,也就是裝飾者類:

/**
 * 
 * @Description: 必須讓CondimentDecorator能夠取代Beverage,所以將CondimentDecorator擴充套件自Beverage類
 */
public abstract class CondimentDecorator extends Beverage {
	// 所有的調料裝飾者都必須重新實現getDescription()方法,稍後說明原因
	public abstract String getDescription();
}
複製程式碼

寫飲料的程式碼

有了上面的基礎,即已經有了基類,那我們就可以愉快的把飲料類實現了。先從濃縮咖啡(Espresso)開始吧。在這,我們需要實現cost()方法以及將描述設定清楚。其他類,在程式碼裡表現,就不在文中體現啦。

/**
 * 
 * @Description:首先,讓Espresso擴充套件自Beverage類,因為Espresso是一種飲料
 * @author:XuYue
 */
public class Espresso extends Beverage {

	public Espresso() {
		// 為了要設定飲料的描述,我們寫了一個構造器,description繼承自Beverage
		description = "Espresso";
	}
	
	// 需要計算Espresso的價錢
	@Override
	public double cost() {
		return 1.99;
	}

}
複製程式碼

寫調料程式碼

還記得上篇中的類圖嗎,根據類圖我們已經完成了抽象元件(Beverage),有了具體元件(HoustBlend),也有了抽象裝飾者(CondimentDecorator)。那麼,就差實現具體的裝飾者了,也就是我們的調料。這裡是列舉Mocha,其他的自行實現哦。小編提供的程式碼裡已經實現啦, 感興趣的小夥伴,可以寫完和小編的PK下。

/**
 * 
 * @Description:
 * 摩卡是一個裝飾者,所以讓它擴充套件自CondimentDecorator
 * CondimentDecorator擴充套件自Beverage
 * @author:XuYue
 */
public class Mocha extends CondimentDecorator {

	Beverage beverage;
	
	public Mocha(Beverage beverage) {
		this.beverage = beverage;
	}
	
	@Override
	public String getDescription() {
		return beverage.getDescription() + " , Mocha";
	}

	@Override
	public double cost() {
		return 0.20 + beverage.cost();
	}

}
複製程式碼

供應咖啡

恭喜你,經歷過之前的準備,是時候坐下來休息休息,點一杯咖啡享受下人生啦。來看看你的裝飾者模式設計出來的系統吧。

寫之前,我們先看看雙倍摩卡咖啡的是怎麼裝飾的吧。其實就是上一篇中的單倍摩卡,再加一層摩卡的裝飾類即可,是不是很神奇呢。

設計模式之裝飾者模式(二)

public class StarbuzzCoffee {

	public static void main(String[] args) {
		// 訂一杯Espresso,不需要調料
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription() + " $" + beverage.cost());
		
		// 訂一杯雙倍Mocha加Whip的DarkRoast()咖啡
		Beverage beverage2 = new DarkRoast();
		// 用Mocha裝飾它
		beverage2 = new Mocha(beverage2);
		// 用第二個Mocha裝飾它
		beverage2 = new Mocha(beverage2);
		// 用Whip裝飾它
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
		
		// 訂一杯調料為Soy、Mocha、Whip的HouseBlend咖啡
		Beverage beverage3 = new HouseBlend();
		beverage3 = new Soy(beverage3);
		beverage3 = new Mocha(beverage3);
		beverage3 = new Whip(beverage3);
		System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
		
	}
}

// 輸出結果
Espresso $1.99
Dark Roast Coffee , Mocha , Mocha , Whip $1.49
House Blend Coffee , Soy , Mocha , Whip $1.34
複製程式碼

目前為止,我們已經把上篇遺留下來的類圖轉換成了程式碼實現出來。當我們在後面介紹到工廠和生成器模式的時候,將會有更好的方式建立被裝飾者物件。所以,儘管現在的裝飾者模式存在部分缺陷,但不妨礙我們對這個模式的學習,後續的增加,只是對模式有更加深刻的認知。

所以,這次的內容就先到這裡。下一篇,我們針對性的對現有JDK中的裝飾者模式舉個例子,並對裝飾者模式做出總結。

留個小習題,在這次講的過程中我們是加了調料, 那咖啡廳裡現在都會有杯子的大小,小杯、中杯、大杯,並收取相應的價錢,該如何編寫呢?先拋個磚,我們在Beverage類中加上getSize()和setSize()。下次小編會給出答案噢。

PS:程式碼已經上傳,需要檢視的朋友點選此處HeadFirstDesign

推薦閱讀

設計模式之裝飾者模式(一)

愛生活,愛學習,愛感悟,愛挨踢

設計模式之裝飾者模式(二)

相關文章