设计模式---装饰者模式

本文探讨了如何使用装饰者模式在星巴克咖啡项目中提高扩展性和维护性,通过定义抽象的Drink类和ConcreteComponent如Coffee及其子类,以及Decorator类来动态添加调料选项,有效避免了类爆炸问题。通过实例展示,展示了如何优雅地组合单品咖啡和调料,体现了开闭原则的应用。
摘要由CSDN通过智能技术生成

问题引出:星巴克咖啡订单项目
咖啡种类/单品咖啡:Espresso(意大利浓咖)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
调料:Mik、Soy(豆浆)、Chocolate
要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
使用 OO 的来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以单品咖啡+调料组合
在这里插入图片描述
● 1)Drink 是一个抽象类,表示饮料
● 2)description 就是对咖啡的描述,比如咖啡的名字
● 3)cost 方法就是计算费用,Drink 类中做成一个抽象方法
● 4)Decaf 就是单品咖啡,继承 Drink,并实现 cost
● 5)Espresso && Milk 就是单品咖啡+调料,这个组合很多
● 6)问题:这样设计,会有很多类。当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,出现类爆炸
Milk、Soy、Chocolate 可以设计为 Boolean,表示是否要添加相应的调料
问题分析:
1.可以控制类的数量,不至于造成很多的类
2.在增加或者删除调料种类时,代码维护量很大,
3.考虑到用户可以添加多份调料时,可以将hasMilk返回一个对应的int

装饰者模式介绍

1.装饰者模式:动态地将新功能附加到对象上,在对象功能扩展方面,它比继承更有弹性,装饰者模式体香了开闭原则(ocp)
2.这里题都的动态将新功能附加到对象和ocp原则,后面会以实例形式体现
原理:
1.装饰者模式就像打包一个快递,主体比如衣服,玩具,包装就是外面的报纸填充物,硬纸板等,
2.主体(component):比如前面的Drink
3.具体的主体(concreteComponent):比如前面的各个单品咖啡
4.装饰者(Decorator):比如调料
5.component与concretecomponent之间,如果concretecomponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象成一个类

装饰者模式解决星巴克咖啡订单项目

在这里插入图片描述
●Drink 就是抽象类 Component
●ShortBlack 单品咖啡就是具体的主体
●Decorator 是一个装饰类,含有一个被装饰的对象(Drink)
●Decorator 的 cost 方法进行一个费用的叠加,递归地计算价格

装饰者模式下的订单:2份巧克力 + 一份牛奶的 LongBlack
在这里插入图片描述
● Milk 包含了 LongBlack
● 一份 Chocolate 包含了 Milk + LongBlack
● 一份 Chocolate 包含了 Chocolate + Milk + LongBlack
● 这样不管是什么形式的单品咖啡 + 调料组合,通过递归方式可以方便的组合和维护

在这里插入图片描述

// 抽象主体
public abstract class Drink {
    private String desc;
    private Float price;

    public String getDesc() {
        return desc;
    }

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

    public Float getPrice() {
        return price;
    }

    protected void setPrice(Float price) {
        this.price = price;
    }

    public abstract Float cost();
}
// 具体主体
public class Coffee extends Drink {

    @Override
    public Float cost() {
        return super.getPrice();
    }
}
public class Decaf extends Coffee {
    public Decaf() {
        setDesc("无因咖啡");
        setPrice(20.0f);
    }
}
public class Espresso extends Coffee {
    public Espresso() {
        setDesc("意大利浓咖");
        setPrice(30.0f);
    }
}
public class ShortBlack extends Coffee {
    public ShortBlack() {
        setDesc("短黑咖啡");
        setPrice(40.0f);
    }
}
public class LongBlack extends Coffee {
    public LongBlack() {
        setDesc("美式咖啡");
        setPrice(50.0f);
    }
}
//装饰者
public class Decorator extends Drink {
    private Drink drink;

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

    @Override
    public Float cost() {
        return super.getPrice() + drink.cost();
    }
}
public class Milk extends Decorator {
    public Milk(Drink drink) {
        super(drink);
        setDesc("牛奶");
        setPrice(3.0f);
    }
}
public class Soy extends Decorator {
    public Soy(Drink drink) {
        super(drink);
        setDesc("豆浆");
        setPrice(4.0f);
    }
}
public class Chocolate extends Decorator {
    public Chocolate(Drink drink) {
        super(drink);
        setDesc("巧克力");
        setPrice(5.0f);
    }
}
// 调用者
public class CoffeeBar {
    public static void main(String[] args) {
        Drink drink = new Espresso();
        System.out.println("意大利浓咖:" + drink.cost() + "美元"); // 意大利浓咖:30.0美元

        drink = new Milk(drink);
        System.out.println("意大利浓咖 + 1份牛奶:" + drink.cost() + "美元"); // 意大利浓咖 + 1份牛奶:33.0美元

        drink = new Chocolate(drink);
        System.out.println("意大利浓咖 + 1份牛奶 + 1份巧克力:" + drink.cost() + "美元"); // 意大利浓咖...:38.0美元

        drink = new Chocolate(drink);
        System.out.println("意大利浓咖 + 1份牛奶 + 2份巧克力:" + drink.cost() + "美元"); // 意大利浓咖...:43.0美元
    }
}

源码分析

java 的 IO 结构,FilterlnputStream 就是一个装饰者
在这里插入图片描述

// 是一个抽象类,即Component
public abstract class InputStream implements Closeable {} 
// 是一个装饰类,即Decorator
public class FilterInputStream extends InputStream { 
    protected volatile InputStream in;
    protected FilterInputStream(InputStream in) {
        this.in = in;
    }
}
// FilterInputStream子类,也继承了被装饰的对象 in
public class DataInputStream extends FilterInputStream implements DataInput { 
    public DataInputStream(InputStream in) {
        super(in);
    }

1.InputStream 是抽象类,类似我们前面讲的 Drink
2.FileInputStream 是 InputStream 子类,类似我们前面的 DeCaf、LongBlack
3.FilterInputStream 是 InputStream 子类,类似我们前面的 Decorator,修饰者
4.DataInputStream 是 FilterInputStream 子类,类似前面的Milk,Soy等,具体的修饰者
5.FilterInputStream 类有protected volatile InputStream in;,即含被装饰者
6.分析得出在 JDK 的 IO 体系,就是使用装饰者模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值