装饰者模式

      装饰者模式指的是在不改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。装饰者可以动态地将责任附加到对象上。

装饰者模式组成结构

  • 抽象构件 (Component):给出抽象接口或抽象类,以规范准备接收附加功能的对象。
  • 具体构件 (ConcreteComponent):定义将要接收附加功能的类。
  • 抽象装饰 (Decorator):装饰者共同要实现的接口,也可以是抽象类。
  • 具体装饰 (ConcreteDecorator):持有一个 Component 对象,负责给构件对象“贴上”附加的功能。

UML类图

       

 

 使用场景

  • 需要扩展一个类的功能,或给一个类添加附加职责。
  • 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

星巴兹咖啡订单系统

       星巴兹店提供了各式各样的咖啡,以及各种咖啡调料。为了适应饮料需求供应,所以让你设计一个更新订单系统

继承

      

 

      在购买咖啡时,可以要求在咖啡中添加各种调料,例如:豆浆 (Soy)、摩卡 (Mocha)、奶泡等。由于各种调料的价格不相同,所以订单系统必须要考虑这些因素。

继承类图

      

 

       类爆炸

装饰者登场

       装饰者模式涉及到的一个重要的设计原则 (当然还涉及到了其他的设计原则,比如多用组合,少用继承等):类应该对扩展开放,对修改关闭。

       在设计过程中,我们允许类容易扩展,在不修改原有代码的情况下,就可以扩展新的行为。这样的设计具有弹性可以应对改变,可以接受新的功能来应对新的需求。

      想要摩卡和豆浆深焙咖啡,那么,要做的是:

  1. 拿一个深焙咖啡 (DarkRoast) 对象
  2. 以摩卡 (Mocha) 装饰它
  3. 以豆浆 (Soy) 装饰它
  4. 调用 cost() 方法,并依赖委托将调料的价钱加上去

  

装饰者模式设计图

   

 

饮料 Beverage 抽象类

public abstract class Beverage {
    protected String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    /**
     * 价格
     *
     * @return
     */
    public abstract double getCost();
}

浓咖啡 Espresso 类

public class Espresso extends Beverage {

    @Override
    public String getDescription() {
        return "Espresso";
    }

    @Override
    public double getCost() {
        return 1.99;
    }
}

黑咖啡HouseBlend类

public class HouseBlend extends Beverage {

    @Override
    public String getDescription() {
        return "House Blend Coffee";
    }

    @Override
    public double getCost() {
        return 0.8;
    }
}

调料类CondimentDecorator类

public abstract class CondimentDecorator extends Beverage {

    public abstract String getDescription();
}

摩卡Mocha类

public class Mocha extends CondimentDecorator {

    private Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Mocha";
    }

    @Override
    public double getCost() {
        return 0.2 + beverage.getCost();
    }
}

豆浆Soy类

public class Soy extends CondimentDecorator {

    private Beverage beverage;

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Soy";
    }

    @Override
    public double getCost() {
        return 0.1 + beverage.getCost();
    }
}

测试类

@Slf4j
public class BuyCoffee {

    public static void main(String[] args) {
        //两份摩卡加一份豆浆的浓咖啡
        Beverage espresso = new Espresso();
        espresso = new Mocha(espresso);
        espresso = new Mocha(espresso);
        espresso = new Soy(espresso);

        log.info("{} 价格:{}", espresso.getDescription(), espresso.getCost());
    }
}

装饰者模式问题总结

  • 装饰者与被装饰对象有相同的超类型 (DarkRoast 与装饰类 Mocha 和 Soy 都继承自 Beverage(饮料))。
  • 可以使用一个或多个装饰对象包装一个对象。
  • 因为装饰者与被装饰者具有相同的超类型,在任何需要原始对象的情况下,都可以用装饰过的对象去代替它。
  • 装饰者可以在所委托被装饰者的行为之前与之后,加上自己的行为,以达到特定的目的。
  • 对象可以在任何时候被装饰,所以在运行时动态地、不限量地用你喜欢的装饰者去装饰对象

 

posted on 2022-04-01 11:50  溪水静幽  阅读(98)  评论(0)    收藏  举报