bboyjing's blog

HeadFirst设计模式三【装饰者模式】

装饰者模式可以使用对象组合的方式,做到在运行时装饰类,能够在不修改任何底层代码的情况下,给对象赋予新的职责。本章可以称为:给爱用继承的人一个全新的设计眼界。下面我们就来学习下这个模式。

场景描述

书中描述了一个制作饮料的场景,比如星巴克的咖啡,制作一杯咖啡可以加其他配料,而最终的价格会根据调料的不同而不同。装饰者模式的实现方式是以咖啡为基底,使用配料装饰器来装饰,最终形成的就是一杯我们需要的咖啡。概念说不太清楚,直接看下面代码会更直观。

代码示例

  1. 定义饮料抽象类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public abstract class Beverage {
    String description = "Unknown Beverage";
    public String getDescription() {
    return description;
    }
    public abstract double cost();
    }
  2. 定义调料装饰者抽象类,继承饮料

    1
    2
    3
    4
    public abstract class CondimentDecorator extends Beverage {
    @Override
    public abstract String getDescription();
    }
  3. 定义咖啡实体类,继承饮料

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class HouseBlend extends Beverage {
    /**
    * 构造函数中指定咖啡的名称描述
    */
    public HouseBlend() {
    description = "House Blend Coffee";
    }
    @Override
    public double cost() {
    return 0.89;
    }
    }
  4. 定义调料实体类,继承调料装饰者,装饰器中记录了被装饰者。Soy和Wip调料类似

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Mocha extends CondimentDecorator {
    /**
    * 示例变量记录饮料,也就是被装饰者
    */
    Beverage beverage;
    public Mocha(Beverage beverage) {
    this.beverage = beverage;
    }
    /**
    * 饮料加调料的完整描述
    *
    * @return
    */
    @Override
    public String getDescription() {
    return beverage.getDescription() + ", Mocha";
    }
    @Override
    public double cost() {
    return 0.20 + beverage.cost();
    }
    }
  5. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Test {
    public static void main(String[] args) {
    Beverage houseBlend = new HouseBlend();
    houseBlend = new Syo(houseBlend);
    houseBlend = new Mocha(houseBlend);
    houseBlend = new Whip(houseBlend);
    System.out.println(houseBlend.getDescription() + " $ " + houseBlend.cost());
    }
    }

开始不太理解,看完代码之后,感受到这个模式的好处了,可以一层层装饰,无限叠加属性。其方法的调用方式有点类似递归,从description的打印可以看出,beverage一层层调用,从最后一个装饰器开始,一直调用到被装饰者的description方法。最先打印出需要装饰的主类的名称,然后是第一个装饰器,依次类推。另外一个重点在于,装饰者和被装饰者必须是一样的类型,也就是有共同的超类。这里使用了继承,但是是利用继承达到类型匹配,而不是利用继承来获得行为。

总结

装饰者模式的无限包装确实给我们一个全新的眼界,不能再局限于通过继承获得行为了。但是配料都继承饮料感觉有点怪怪的,又不能包装成别的类型。继续往后学吧,说不定有更好的模式去实现。