Head First设计模式(三)、装饰者模式

装饰者模式:

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

特点:

1、装饰者和被装饰对象有相同的超类型。

2、你可以用一个或多个装饰者包装一个对象。

3、既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。

4、装饰者可以再所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。

5、对象可以在任何时候被装饰所以可以在运行时动态地、不限量地用你先的装饰者来装饰对象。

Head First设计模式(三)、装饰者模式

实例:

购买咖啡是,可以要求在其中假如各种调料,例如:豆浆、摩卡、或者奶泡,根据所加入的调料收取不同的费用。

以装饰者模式构造:

Head First设计模式(三)、装饰者模式

Head First设计模式(三)、装饰者模式

类图:

Head First设计模式(三)、装饰者模式

话不多说,直接上代码:

/**

 * 饮料类

 *

 */

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());

    }

}