设计模式之装饰者模式

装饰者模式定义

动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)

装饰者模式原理

image

  • 装饰者模式就像打包一个快递
    • 主体:例如陶瓷、衣服、零食等(Component)
    • 包装:例如报纸填充、泡沫填充、纸板、木板等(Decorator)
  • Component:主体例如前面的Drink
  • ConcreteComponent:具体的主体,例如各个单品
  • Decorator:装饰者吗,例如各种调料
  • 在如图的ConcreteComponent与Component之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类
    核心思想:将被装饰者组合进装饰者中,并且装饰者和被装饰者都要继承同一个抽象类,便于装饰者进行某些递归操作(也可以说是提高了可扩展性和增强了弹性)

案例

星巴克订单项目

  • 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无咖啡因咖啡)
  • 调料:Milk、Soy(豆浆)、Chocolate
  • 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
  • 使用OO(面向对象)来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以点单品咖啡和调料组合

方案一(最差的解决方案)

image

第一种方案解决星巴克咖啡订单问题分析

  • Drink是一个抽象类,表示饮料
  • desc就是对咖啡的描述,比如咖啡的名字
  • cost()方法就是计算费用,Drink类中做成一个抽象的方法
  • Decaf就是单品,继承了Drink,并且实现了cost()
  • Espresso&&Milk&&Soy就是单品咖啡+调料,这种组合很多
  • 问题:这样设计会有很多类,当我们新增一个咖啡或者一种调料时,类的数量就会倍增(即就是类爆炸)

方案二(相较于方案一好一点)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RWa8gO7D-1613490983864)(http://626372.haituie.cn/626372/learning/java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/coffee2.png)]

第二种方案解决星巴克咖啡订单问题分析

  • 将调料内置到Drink类中,就不会造成类爆炸的情况
  • 但是在增加或者删除调料种类时,代码维护量依然很大
  • 考虑使用装饰者模式

方案三(装饰者模式推荐使用)

  • Drink类就是抽象类Component
  • ShortBlack就是单品类
  • Decorator就是装饰类,含有一个被装饰的对象Drink drink
  • Decorator的cost方法进行一个费用的叠加计算(递归进行)
    image
    装饰者模式下的订单:两份巧克力加一份牛奶的LongBlack
  • Milk包含了LongBlack
  • 一份Chocolate包含了(Milk+LongBlack)
  • 一份Chocolate包含了(Chocolate+Milk+LongBlack)
  • 这样不管是什么形式的单品咖啡+调料组合,通过递归的方式可以方便的组合和维护
    image
public abstract class Drink {
    public String desc;
    private float price;

    public String getDesc() {
        return desc;
    }

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

    public float getPrice() {
        return price;
    }

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

    abstract float cost();
}
public class Coffee extends Drink {
    @Override
    float cost() {
        return super.getPrice();
    }
}
public class Espresso extends Coffee {
    public Espresso() {
        setDesc("意大利咖啡");
        setPrice(20.5f);

    }
}
public class LongBlack extends Coffee {
    public LongBlack() {
        setDesc("LongBlack");
        setPrice(30.5f);
    }
}
public class ShortBlack extends Coffee {
    public ShortBlack() {
        setDesc("ShortBlack");
        setPrice(28.4f);
    }
}
public class Decorator extends Drink {
    private Drink drink;

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

    /**
     * 这里计算是递归计算的
     * @return
     */
    @Override
    float cost() {
        return super.getPrice()+drink.cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + super.getPrice() + drink.getDesc();
    }
}
public class Chocolate extends Decorator {
    public Chocolate(Drink drink) {
        super(drink);
        setDesc("巧克力");
        setPrice(5.0f);
    }
}
public class Milk extends Decorator {
    public Milk(Drink drink) {
        super(drink);
        setDesc("牛奶");
        setPrice(5.0f);
    }
}
public class Soy extends Decorator {
    public Soy(Drink drink) {
        super(drink);
        setDesc("豆浆");
        setPrice(3.0f);
    }
}
public class CoffeeBar {
    /**
     * 装饰者模式下单:两份巧克力加一份牛奶的单品咖啡
     */
    public static void main(String[] args) {
        Drink order = new LongBlack();
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Milk(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Chocolate(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Chocolate(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        System.out.println("#############################");
        order = new ShortBlack();
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Milk(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Chocolate(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Chocolate(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        System.out.println("#############################");
        order = new Espresso();
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Milk(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Chocolate(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
        order = new Chocolate(order);
        System.out.println("当前费用"+order.cost());
        System.out.println("当前描述"+order.getDesc());
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值