设计模式-装饰器模式

装饰器模式

  • 简述
  • 问题背景
  • 解决方案1:传统方案
  • 解决方案2:解决类爆炸
  • 解决方案3:装饰者模式
    • 装饰者模式原理
    • 装饰者模式解决星巴克咖啡订单问题
  • 代码示例:
  • 源码

简述

装饰者模式的定义为:动态的给一个对象添加其它功能。
从扩展性来说,这种方式比继承更有弹性,更加灵活,装饰者模式也体现了开闭原则(OCP)。

问题背景

星巴克咖啡订单项目(咖啡馆) :
1)咖啡种类/单品咖啡: Espresso(意大利浓咖啡)、ShortBlack、Decaf(无因咖啡)、LongBlack(美式咖啡)
2)配料: Milk、Soy(豆浆)、Chocolate
3)要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
4)使用OO的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合

解决方案1:传统方案

设计模式-装饰器模式_第1张图片
1)Drink是一个抽象类,表示饮品。
2)desc是对这个饮品的描述, 比如单品咖啡的名字,单品咖啡+配料
3)cost()方法是这个饮品的费用

最普通的设计就是有多少种组合那就写多少种类,这样排列组合下来类的数量会成倍增加,就会出啊先类爆炸。

解决方案2:解决类爆炸

设计模式-装饰器模式_第2张图片
1)通过往单品咖啡类中增加配料来减少类爆炸。
2)在增加或者删除配料种类时,代码的维护量很大,要维护每一个单品咖啡的类。
3)考虑使用装饰者模式

解决方案3:装饰者模式

装饰者模式原理

设计模式-装饰器模式_第3张图片
这个就是装饰者模式的UML类图,我们来解释一下:
1)Component是一个所有类的超类,都要继承它。
2)ConcreteComponent是被装饰者类
3)Decorator是所有装饰者的超类,装饰者类都要继承Decorator
4)装饰者和被装饰者有着共同的超类型,这一点很重要,因为装饰者必须能够取代被装饰者。这样,装饰者才能在被装饰者的基础上,加上自己的行为,以增强被装饰者的能力。
5)一个被装饰者可以被多个装饰者依次包装,这个包装行为是动态的,不限次数的。

装饰者模式解决星巴克咖啡订单问题

设计模式-装饰器模式_第4张图片

我们来解释一下:
1)Drink就是所有饮品的超类,就是前面所说的Component
2)Coffee是我们单品咖啡的父类
3)Decorator就是配料类的超类,配料就是装饰者。
4)如果我们点了单品咖啡,然后有加了配料,那么我们可以将这个单品咖啡类放到装饰类的Drink属性上,因为都继承了Drink,所以被装饰了的类也是Drink对象,所以如果我们再加配料,仍然可以将这个对象放到新的装饰者(配料)对象中的Drink属性上。

设计模式-装饰器模式_第5张图片

代码示例:

Drink类

public abstract class Drink {

    private String desc;
    private Double price = 0.00;

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public abstract Double cost();
}

配料超类(装饰者类)

public class Decorator extends Drink{

    private Drink obj;

    public Decorator(Drink obj) {
        this.obj = obj;
    }

    @Override
    public Double cost() {

        return super.getPrice() + obj.cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + " " + super.getPrice() + " " + obj.getDesc();
    }
}

Coffee类

public class Coffee extends Drink{
    @Override
    public Double cost() {
        // 对于单体咖啡就是价格
        return super.getPrice();
    }
}

单体咖啡类

public class Espresso extends Coffee{
    public Espresso() {
        setDesc("Espresso");
        setPrice(3.00);
    }
}

public class LongBlack extends Coffee{
    public LongBlack() {
        setDesc("ShortBlack");
        setPrice(5.00);
    }
}

public class ShortBlack extends Coffee{
    public ShortBlack() {
        setDesc("ShortBlack");
        setPrice(4.00);
    }
}

配料类

public class Chocolate extends Decorator{
    public Chocolate(Drink obj) {
        super(obj);
        setDesc("Chocolate");
        setPrice(1.00);
    }
}

public class Milk extends Decorator{
    public Milk(Drink obj) {
        super(obj);
        setDesc("Milk");
        setPrice(1.10);
    }
}

public class Soy extends Decorator{
    public Soy(Drink obj) {
        super(obj);
        setDesc("Soy");
        setPrice(1.20);
    }
}

咖啡店类

public class CoffeeBar {
    public static void main(String[] args) {
        // 装饰者模式下订单:2份Chocolate + 1份Mikl的LongBlack

        // 1.点一份LongBlack
        Drink order = new LongBlack();
        System.out.println("单体咖啡" + order.getDesc() + "的费用:" + order.cost());

        // 2.加入一份Mikl
        order = new Milk(order);
        System.out.println("单体咖啡" + order.getDesc() + "的费用:" + order.cost());

        // 3.加入两份巧克力
        order = new Chocolate(order);
        order = new Chocolate(order);
        System.out.println("单体咖啡" + order.getDesc() + "的费用:" + order.cost());
    }
}

源码

GitHub地址:design-patterns

你可能感兴趣的:(设计模式,设计模式,装饰器模式,uml)