【Head First设计模式】-Decorator模式
一、要完成的任务
星巴兹(Starbuzz)是以扩张速度最快而闻名的咖啡连锁店。如果你在街角看到它的店,在对面街上肯定还会看到另一家。因为扩张速度实在太快了,他们准备更新订单系统,以合乎他们的饮料供应要求。他们原先的类设计是这样的……
购买咖啡时,也可以要求在其中加入各种调料,例如:蒸奶(Steamed Milk)、豆浆(Soy)、摩卡(Mocha,也就是巧克力风味)或覆盖奶泡。星巴兹会根据所加入的调料收取不同的费用。所以订单系统必须考虑到这些调料部分。
二、Decorator模式
1、一个原则
类应该对扩展开放,对修改关闭
2、定义装饰者模式
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
3.分析任务
4.设计任务
三、代码实现
1.定义抽象类
(1)饮料抽象类Beverage
Beverage.java
package
com.sterning.ch3_decorator;
/**/ /*
* Beverage是一个抽象类,有两个方法
*/
public abstract class Beverage {
public String description="Unknown Beverage";
/**//*
* getDescription()已经在此实现了,但是cost()必须在子类中实现
*/
public String getDescription() {
return description;
}
public abstract double cost();
}
/**/ /*
* Beverage是一个抽象类,有两个方法
*/
public abstract class Beverage {
public String description="Unknown Beverage";
/**//*
* getDescription()已经在此实现了,但是cost()必须在子类中实现
*/
public String getDescription() {
return description;
}
public abstract double cost();
}
(2)调料抽象类CondimentDecorator
CondimentDecorator.java
package
com.sterning.ch3_decorator;
/**/ /*
* 首先,必须让CondimentDecorator能够取代Beverage,所以将CondimentDecorator扩展自Beverage类
*/
public abstract class CondimentDecorator extends Beverage {
//所有的调料装饰者都必须重新实现getDescription()方法.
public abstract String getDescription();
}
/**/ /*
* 首先,必须让CondimentDecorator能够取代Beverage,所以将CondimentDecorator扩展自Beverage类
*/
public abstract class CondimentDecorator extends Beverage {
//所有的调料装饰者都必须重新实现getDescription()方法.
public abstract String getDescription();
}
2.饮料实现
(1)Espresso
Espresso.java
package
com.sterning.ch3_decorator;
/**/ /*
* 首先,必须让CondimentDecorator能够取代Beverage,所以将CondimentDecorator扩展自Beverage类
*/
public abstract class CondimentDecorator extends Beverage {
//所有的调料装饰者都必须重新实现getDescription()方法.
public abstract String getDescription();
}
/**/ /*
* 首先,必须让CondimentDecorator能够取代Beverage,所以将CondimentDecorator扩展自Beverage类
*/
public abstract class CondimentDecorator extends Beverage {
//所有的调料装饰者都必须重新实现getDescription()方法.
public abstract String getDescription();
}
(2)HouseBlend
HouseBlend.java
package
com.sterning.ch3_decorator.drink;
import com.sterning.ch3_decorator.Beverage;
public class HouseBlend extends Beverage {
public HouseBlend() {
description="House Blend Coffee";
}
@Override
public double cost() {
return 0.89;
}
}
import com.sterning.ch3_decorator.Beverage;
public class HouseBlend extends Beverage {
public HouseBlend() {
description="House Blend Coffee";
}
@Override
public double cost() {
return 0.89;
}
}
(3)DarkRoast
DarkRoast.java
package
com.sterning.ch3_decorator.drink;
import com.sterning.ch3_decorator.Beverage;
public class DarkRoast extends Beverage {
public DarkRoast() {
description="Dark Roast Coffee";
}
@Override
public double cost() {
return 0.99;
}
}
import com.sterning.ch3_decorator.Beverage;
public class DarkRoast extends Beverage {
public DarkRoast() {
description="Dark Roast Coffee";
}
@Override
public double cost() {
return 0.99;
}
}
(4)Decaf
Decaf.java
package
com.sterning.ch3_decorator.drink;
import com.sterning.ch3_decorator.Beverage;
public class Decaf extends Beverage {
public Decaf() {
description="Decaf Coffee";
}
@Override
public double cost() {
return 1.05;
}
}
import com.sterning.ch3_decorator.Beverage;
public class Decaf extends Beverage {
public Decaf() {
description="Decaf Coffee";
}
@Override
public double cost() {
return 1.05;
}
}
3.调料实现
(1)Mocha
Mocha.java
package
com.sterning.ch3_decorator.condiment;
import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;
public class Mocha extends CondimentDecorator {
/**//*
* 要让Mocha能够引用一个Beverage,做法如下:一是用一个实例变量记录饮料,也就是被装饰者.
* 二是想办法让装饰者(饮料)记录到实例变量中,即把饮料当作构造器的参数,再由构造器将此饮料记录在实例变量中
*/
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
/**//*
* 我们希望叙述不只是描述饮料,而是完整的连调料都描述出来
*/
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
/**//*
* 要计算带Mocha饮料的价钱,首先把调用委托给装饰对象,以计算价钱,然后再加上Mocha的价钱,得到最后结果
*/
return 0.20+beverage.cost();
}
}
import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;
public class Mocha extends CondimentDecorator {
/**//*
* 要让Mocha能够引用一个Beverage,做法如下:一是用一个实例变量记录饮料,也就是被装饰者.
* 二是想办法让装饰者(饮料)记录到实例变量中,即把饮料当作构造器的参数,再由构造器将此饮料记录在实例变量中
*/
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
/**//*
* 我们希望叙述不只是描述饮料,而是完整的连调料都描述出来
*/
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
/**//*
* 要计算带Mocha饮料的价钱,首先把调用委托给装饰对象,以计算价钱,然后再加上Mocha的价钱,得到最后结果
*/
return 0.20+beverage.cost();
}
}
(2)Soy
Soy.java
package
com.sterning.ch3_decorator.condiment;
import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
return .15 + beverage.cost();
}
}
import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
return .15 + beverage.cost();
}
}
(3)Whip
Whip.java
package
com.sterning.ch3_decorator.condiment;
import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
4.测试类StarbuzzCoffee
StarbuzzCoffee.java
package
com.sterning.ch3_decorator;
import com.sterning.ch3_decorator.condiment.Mocha;
import com.sterning.ch3_decorator.condiment.Soy;
import com.sterning.ch3_decorator.condiment.Whip;
import com.sterning.ch3_decorator.drink.DarkRoast;
import com.sterning.ch3_decorator.drink.Espresso;
import com.sterning.ch3_decorator.drink.HouseBlend;
public class StarbuzzCoffee {
public static void main(String args[]){
/**//*
* 订一杯Espresso,不需要调料,打印出它的描述和价钱.
*/
Beverage beverage=new Espresso();
System.out.println(beverage.getDescription()+" $"+beverage.cost());
/**//*
* 制造一个DarkRoast对象,用Mocha,Whip装饰它
*/
Beverage beverage2=new DarkRoast();
beverage2=new Mocha(beverage2);
beverage2=new Mocha(beverage2);
beverage2=new Whip(beverage2);
System.out.println(beverage2.getDescription()+" $"+beverage2.cost());
/**//*
* 最后,再来一杯调料为豆浆,摩卡\奶泡的HouseBlend咖啡
*/
Beverage beverage3=new HouseBlend();
beverage3=new Soy(beverage3);
beverage3=new Mocha(beverage3);
beverage3=new Whip(beverage3);
System.out.println(beverage3.getDescription()+" $"+beverage3.cost());
}
}
import com.sterning.ch3_decorator.condiment.Mocha;
import com.sterning.ch3_decorator.condiment.Soy;
import com.sterning.ch3_decorator.condiment.Whip;
import com.sterning.ch3_decorator.drink.DarkRoast;
import com.sterning.ch3_decorator.drink.Espresso;
import com.sterning.ch3_decorator.drink.HouseBlend;
public class StarbuzzCoffee {
public static void main(String args[]){
/**//*
* 订一杯Espresso,不需要调料,打印出它的描述和价钱.
*/
Beverage beverage=new Espresso();
System.out.println(beverage.getDescription()+" $"+beverage.cost());
/**//*
* 制造一个DarkRoast对象,用Mocha,Whip装饰它
*/
Beverage beverage2=new DarkRoast();
beverage2=new Mocha(beverage2);
beverage2=new Mocha(beverage2);
beverage2=new Whip(beverage2);
System.out.println(beverage2.getDescription()+" $"+beverage2.cost());
/**//*
* 最后,再来一杯调料为豆浆,摩卡\奶泡的HouseBlend咖啡
*/
Beverage beverage3=new HouseBlend();
beverage3=new Soy(beverage3);
beverage3=new Mocha(beverage3);
beverage3=new Whip(beverage3);
System.out.println(beverage3.getDescription()+" $"+beverage3.cost());
}
}
源代码下载:ch3_decorator.rar