Head First设计模式(三)、装饰者模式
装饰者模式:
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
特点:
1、装饰者和被装饰对象有相同的超类型。
2、你可以用一个或多个装饰者包装一个对象。
3、既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
4、装饰者可以再所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
5、对象可以在任何时候被装饰所以可以在运行时动态地、不限量地用你先的装饰者来装饰对象。
实例:
购买咖啡是,可以要求在其中假如各种调料,例如:豆浆、摩卡、或者奶泡,根据所加入的调料收取不同的费用。
以装饰者模式构造:
类图:
话不多说,直接上代码:
/**
* 饮料类
*
*/
public abstract class Beverage {
//描述
String description = "Unknown Beverage";
public String getDescription(){
return description;
}
//结算方法
public abstract double cost();
}
/**
* 调料抽象类,也就是装饰者类
*
*/
//必须让CondimentDecorator能够取代Beverage,所以将CondimentDecorator扩展自Beverage
public abstract class CondimentDecorator extends Beverage{
//所有调料装饰者必须重新实现此方法
public abstract String getDescription();
}
/**
* 浓缩咖啡
*
*/
public class Espresso extends Beverage{
public Espresso(){
//为了设置饮料的描述,我们写了一个构造器
description = "Espresso";
}
@Override
public double cost() {
//饮料的价钱
return 1.99;
}
}
/**
* 摩卡装饰者
*
*/
public class Mocha extends CondimentDecorator{
//要让mocha能够引用一个Beverage,做法如下
//1、用一个实例变量记录饮料,也就是被装饰者
Beverage beverage;
//2、想办法让被装饰者被记录到实例变量中,这里的做法是:把饮料当做构造器的参数,再由构造器将此饮料记录在实例变量中
public Mocha(Beverage beverage){
this.beverage = beverage;
}
@Override
public String getDescription() {
// 我们希望描述不只是描述饮料,而是完整的连调料也描述出来,所以首先利用委托的做法,得到一个描述,然后在其后加上附加的叙述
return beverage.getDescription() + ",Mocha";
}
@Override
public double cost() {
//需要计算带mocha饮料的价钱,首先把调用委托给被装饰对象,以计算价格,然后再加上摩卡的价钱,得到最后结果
return 0.2 + beverage.cost();
}
}
public class CoffeeTest {
//测试类
public static void main(String[] args) {
//订一杯浓缩咖啡,不需要饮料
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" +beverage.cost());
//订一杯浓缩咖啡,需要mocha
Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2);
System.out.println(beverage2.getDescription() + " $" +beverage2.cost());
}
}