[0310].第10节.装饰器模式

以咖啡订单引入装饰者模式:

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

1.结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象

2.由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性


1.装饰者模式

1.1.定义:

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

2.2.结构:

  • 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象,比如类似前面的 Drink
  • 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责,比如前面的各个单品咖啡
  • 抽象装饰(Decorator)角色继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
  • 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任,

装饰者模式就像打包一个快递

  • 主体:比如陶瓷、衣服 (Component) // 被装饰者
  • 包装:比如报纸填充、塑料泡沫、纸板、木板(Decorator)

如果具体构件类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象成一个类,就是抽象装饰着


2.案例实现:

2.1.传统方案1:

a.类图设计:

  • 1.Drink是一个抽象类,表示饮料
  • 2.des是对咖啡的描述,如咖啡的名称
  • 3.cost方法是计算费用,Drink类做成一个抽象方法,具体的咖啡种类通过继承抽象的Drink类来实现
    在这里插入图片描述

b.缺点:

  • 1.比较差的设计样例,耦合度过高
  • 2.如果说要添加扩展新的单品咖啡或者组合口味的咖啡的时候,咖啡的种类会很多,咖啡+调料的组合会更多,那么就会导致类的数量增加,就会引发"类爆炸"

2.2.传统方案2:

a.类图:

  • 将调料内置到Drink类在这里插入图片描述

b.缺点:

  • 将调料内置到Drink类,不会造成类数量过多,但是添加或者删除调味品的种类时,需要改动维护,代码的维护量也很大

2.3.装饰者模式实现:

a.类图设计:

在这里插入图片描述
在这里插入图片描述

b.编码实现:

  • 1.抽象构件(Component)角色:抽象类饮品
public abstract class Drink {
    //对饮品的描述
    private String description;
    //价格
    private float price;
 
    //计算价格,由子类实现
    public abstract float cost();
 
    public void setDescription(String description) {
        this.description = description;
    }
 
    public String getDescription() {
        return description;
    }
 
    public void setPrice(float price) {
        this.price = price;
    }
 
    public float getPrice() {
        return price;
    }
}
  • 2.对众多具体构件的抽象:缓冲类Coffee
public class Coffee extends Drink{
    @Override
    public float cost() {
        return super.getPrice();
    }
}
  • 3.具体构件类:两种Coffee
public class LongBlackCoffee extends Coffee{
    public LongBlackCoffee(){
        setDescription("一份美式咖啡");
        setPrice(7.0f);
    }
}
public class ShortBlackCoffee extends Coffee {
    public ShortBlackCoffee(){
        setDescription("一份浓缩咖啡");
        setPrice(5.0f);
    }
}
  • 4.装饰者Decorator类:需要继承和聚合被装饰类
//装饰者
public class Decorator extends Drink{
    //被装饰者;
    private Drink drink;
 
    public Decorator(Drink drink){
        this.drink = drink;
    }
 
    @Override
    public float cost() {
        return super.getPrice() + drink.cost();
    }
 
    @Override
    public String getDescription(){
        return drink.getDescription() + " && " +
                super.getDescription() + super.getPrice();
    }
}
  • 5.两种调味品:
public class Milk extends Decorator{
    public Milk(Drink drink) {
        super(drink);
        setDescription("一份牛奶");
        setPrice(2.0f);
    }
}
public class Chocolate extends Decorator{
    public Chocolate(Drink drink) {
        super(drink);
        setDescription("一份巧克力");
        setPrice(1.0f);
    }
}

c.

  • 1.模拟客户下单:加两份巧克力和一份牛奶的咖啡
    在这里插入图片描述
public class Client {
    public static void main(String[] args) {
        //两份巧克力+一份牛奶的美式咖啡;
        //1.先点美式咖啡;
        Drink result = new LongBlackCoffee();
        System.out.println("步骤一::" + result.getDescription());
        System.out.println("本次花费==>" + result.cost());
 
        //2.加份牛奶;
        result = new Milk(result);
        System.out.println("步骤二::" + result.getDescription());
        System.out.println("本次花费==>" + result.cost());
 
        //3.加份巧克力;
        result = new Chocolate(result);
        System.out.println("步骤三::" + result.getDescription());
        System.out.println("本次花费==>" + result.cost());
 
        //4.加份巧克力;
        result = new Chocolate(result);
        System.out.println("步骤四::" + result.getDescription());
        System.out.println("最终花费==>" + result.cost());
    }
}
  • 2.输出
步骤一::一份美式咖啡
本次花费==>7.0
步骤二::一份美式咖啡 && 一份牛奶2.0
本次花费==>9.0
步骤三::一份美式咖啡 && 一份牛奶2.0 && 一份巧克力1.0
本次花费==>10.0
步骤四::一份美式咖啡 && 一份牛奶2.0 && 一份巧克力1.0 && 一份巧克力1.0
最终花费==>11.0

3.装饰者模式在 JDK 应用的源码分析

3.1.InputStream类图分析:

  • 1.Java 的 IO 结构,FilterInputStream 就是一个装饰者
    在这里插入图片描述
public class Test {
    public static void main(String[] args) throws IOException {
        DataInputStream dataInputStream = new DataInputStream(new FileInputStream("e:\\a.txt"));
        System.out.println(dataInputStream.read());
        dataInputStream.close();
    }
}

3.2.说明:

  • InputStream 是抽象类,类似前面的Drink
  • FileInputStream、StringBufferInputStream等是InputStream子类,类似前面的浓缩咖啡,美式咖啡
  • FilterInputStream是InputStream子类,类似前面的Decorator修饰者
  • DataInputStream等是FilterInputStream子类,具体的修饰者,类似前面的Milk,Chocolate等
  • FilterInputStream类有protected volatile InputStream in; 即含被装饰者
public class FilterInputStream extends InputStream {
    protected volatile InputStream in;
 
    protected FilterInputStream(InputStream var1) {
        this.in = var1;
    }

分析得出在 JDK 的 IO 体系中,就是使用装饰者模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值