善用設計模式-裝飾者模式

本文整理自百度文庫ppt:http://wenku.baidu.com/link?url=vWUj0YhlLr0C2X8s9tZ_UkZN9pUmgDQz2G7kCAiPLkP83HLaQBQtnSGrJQJ4typ-Av0tqetq-a6T6b7uPTq2_K17j0vGXcypoFCU32YT-dC

案例:星巴茲(Starbuzz)咖啡訂購系統。

最初設計的訂購系統如下圖:


購買咖啡時,每一種咖啡中能添加一種或幾種調料:steamed milk(蒸煮的牛奶), soy(醬油), mocha(摩卡,也稱爲巧克力),和 whipped milk (加了甜點心的牛奶)。每一種調料都要收一點錢,星巴茲(Starbuzz)咖啡訂購系統變成下面的樣子:


顯然上面這種設計是不合理的,後面設計人員再次做了改動,修改後如下圖


這個設計的缺陷
  如果調料的價格改變,我們需要修改現存的代碼。
  如果增加了新的調料,我們需要在基類增加新的方法以及修改cost()方法。
  我們也可能有新的飲料類型。一些飲料類型,例如,冰茶(ice tea),現有的調料可能是不合適的。但是,茶子類仍然後繼承基類的調料方法。
  如果客戶需要雙份mocha,怎麼辦呢?

我們已經看到:附加調料的飲料定價模式,用繼承表示是不合適的;在基類增加調料的實例變量和方法,對一些子類也是不合適的。 這裏,我們試試:以飲料爲主體,用調料“裝飾”飲料。例如,如果客戶需要Dark Roast(焦炒咖啡) ,添加Mocha(摩卡)和Whip(甜點心)。

我們可以:
     取DarkRoast (焦炒咖啡)對象;
     用Mocha (摩卡)對象裝飾它;
     用Whip (甜點心)對象裝飾它;
     調用cost()方法計算價格,總價格的計算需要委託。
     但是,我們怎樣裝飾一個對象?又怎樣委託?

裝飾者模式,動態地給對象添加職責,就擴展功能而言,裝飾者比派生子類提供了更好的柔性。




接下來我們看星巴克訂購的實現代碼:

/**
 * @author pengl
 * 2014-5-7
 * 描述:被裝飾基類 (組件接口) 飲品
 */
public abstract class Beverage {
	protected String description; 
	/**
	 * 飲品描述信息
	 * @return
	 */
	protected String getDescription(){
		return description;
	}
	/**
	 * 計算價格
	 * @return
	 */
	protected abstract double cost();
}

/**
 * @author pengl
 * 2014-5-7
 * 描述:被裝飾者子類(具體組件) 焦烤咖啡
 */
public class DarkRoast extends Beverage{
	public DarkRoast(){
		description = "焦烤咖啡";
	}
	@Override
	protected double cost() {
		return 2.5;
	}
}

/**
 * @author pengl
 * 2014-5-7
 * 描述:被裝飾者子類(具體組件) 家庭混合咖啡
 */
public class HouseBlend extends Beverage{
	public HouseBlend(){
		description = "家庭混合咖啡";
	}
	@Override
	protected double cost() {
		return 1.8;
	}

}

/**
 * @author pengl
 * 2014-5-8
 * 描述:裝飾者基類
 */
public abstract class CondimentDecorator extends Beverage{
	public abstract String getDescription();
}

/**
 * @author pengl
 * 2014-5-8
 * 描述:裝飾者實現類  摩卡
 */
public class Mocha extends CondimentDecorator{
	
	Beverage beverage; 
	public Mocha(Beverage beverage){
		this.beverage = beverage;
	}
	@Override
	public String getDescription() {
		return beverage.getDescription() + ",Mocha";
	}
	@Override
	protected double cost() {
		return 0.7 + beverage.cost();
	}

}

/**
 * @author pengl
 * 2014-5-8
 * 描述:裝飾者實現類  牛奶
 */
public class Milk extends CondimentDecorator{
	
	Beverage beverage; 
	public Milk(Beverage beverage){
		this.beverage = beverage;
	}
	@Override
	public String getDescription() {
		return beverage.getDescription() + ",Milk";
	}
	@Override
	protected double cost() {
		return 0.2 + beverage.cost();
	}
}

/**
 * @author pengl
 * 2014-5-8
 * 描述:客戶端測試類
 */
public class Main {
	public static void main(String[] args) {
		Beverage beverage = new DarkRoast(); // 焦烤咖啡
		System.out.println(beverage.getDescription() + " $" + beverage.cost()); 
		beverage = new Mocha(beverage); //添加摩卡
		System.out.println(beverage.getDescription() + " $" + beverage.cost()); 
		beverage = new Milk(beverage);	//添加牛奶
		System.out.println(beverage.getDescription() + " $" + beverage.cost());
		Beverage beverage2 = new Milk(new HouseBlend()); // 家庭混合咖啡加摩卡加牛奶
		System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
	}
}

接下來我以我公司的業務寫的一個測試裝飾者模式代碼

/**
 * @author pengl
 * 2014-5-9
 * 描述:客戶端測試類
 */
public class Main {
	public static void main(String[] args) {
		IGetLoginInfo loginInfo = new GetLoginBasicInfo();
		//只要基本信息
		System.out.println(loginInfo.getLoginInfo().get("custName")+"--"+loginInfo.getLoginInfo().get("custId"));
		//要基本信息和套餐速率信息
		loginInfo = new GetLoginPackageAndSpeed(new GetLoginBasicInfo());
		System.out.println(loginInfo.getLoginInfo().get("custName")+"--"+loginInfo.getLoginInfo().get("custId")
				+"--"+loginInfo.getLoginInfo().get("speed")+"--"+loginInfo.getLoginInfo().get("package"));
		//要基本信息,套餐速率信息 和費用信息
		loginInfo = new GetLoginAccountBalance(new GetLoginPackageAndSpeed(new GetLoginBasicInfo()));
		System.out.println(loginInfo.getLoginInfo().get("custName")+"--"+loginInfo.getLoginInfo().get("custId")
				+"--"+loginInfo.getLoginInfo().get("speed")+"--"+loginInfo.getLoginInfo().get("package")
				+"--"+loginInfo.getLoginInfo().get("balance")+"--"+loginInfo.getLoginInfo().get("lastDate"));

	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章