• 设计模式-装饰器模式


    简述

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

    问题背景

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

    解决方案1:传统方案

    在这里插入图片描述
    1)Drink是一个抽象类,表示饮品。
    2)desc是对这个饮品的描述, 比如单品咖啡的名字,单品咖啡+配料
    3)cost()方法是这个饮品的费用

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

    解决方案2:解决类爆炸

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

    解决方案3:装饰者模式

    装饰者模式原理

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

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

    在这里插入图片描述

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

    在这里插入图片描述

    代码示例:

    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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    配料超类(装饰者类)

    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Coffee类

    public class Coffee extends Drink{
        @Override
        public Double cost() {
            // 对于单体咖啡就是价格
            return super.getPrice();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    单体咖啡类

    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    配料类

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    咖啡店类

    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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    源码

    GitHub地址:design-patterns

  • 相关阅读:
    音视频开发(一)ffmpeg 简单学习
    excel文档打不开怎么修复?
    OFDM 系统在 AWGN 信道下对不同载波频率偏移 (CFO) 的 BER 灵敏度研究(Matlab代码实现)
    HDFS dfs指令
    Excel也能调用HFSS?
    CPA招新Ⅱ
    C2基础设施威胁情报对抗策略
    JavaScript学习笔记四——数组对象
    【深度学习】特征图的上采样(nn.Upsample)和转置卷积(nn.ConvTranspose2d) | pytorch
    Spring 中BeanFactory和FactoryBean有什么不同之处呢?
  • 原文地址:https://blog.csdn.net/qq_46307070/article/details/130907157