• 二十三种设计模式全面解析-装饰器模式-超越继承的灵活装扮



    软件开发中,我们经常面临需要为对象动态地添加额外的功能或属性的情况。继承是一种常见的解决方案,但它有时会导致类的爆炸性增长和复杂的继承层次结构。在这种情况下,装饰器模式(Decorator Pattern)是一种强大的设计模式,能够帮助我们实现灵活的组合和装饰对象,而无需依赖于继承关系。


    本文将深入解析装饰器模式,包括装饰器模式的基本概念、适用场景、技术要点以及详细的案例代码。让我们一起探索装饰器模式的魅力,为软件设计带来全新的可能性。

    1、什么是装饰器模式?

    装饰器模式属于结构型设计模式,它允许我们在运行时动态地给对象添加新的行为或属性,而无需修改其原始类。装饰器模式通过将对象包装在一个装饰器类中,然后将装饰器类嵌套在其他装饰器类中,从而形成一个装饰器链。


    一个对象可以使用多个类的行为, 包含多个指向其他对象的引用, 并将各种工作委派给引用对象; 继承中的对象则继承了父类的行为, 它们自己能够完成这些工作。


    2、适用场景

    装饰器模式适用于以下情况:

    • 当你需要动态地为对象添加额外的功能,而不影响其他对象。
    • 当你希望通过组合而非继承来实现对象的扩展。
    • 当你有多个不同的功能组合选项,并且想要避免创建大量的子类。

    3、技术要点

    装饰器模式的核心要点包括:

    • 抽象构件(Component):声明封装器和被封装对象的公用接口。

    • 具体构件(Concrete Component):是被封装对象所属的类,它定义了基础行为,但装饰类可以改变这些行为。

    • 基础装饰器 (Base Decorator) :拥有一个指向被封装对象的引用成员变量。该变量的类型应当被声明为通用部件接口,这样它就可以引用具体的部件和装饰。装饰基类会将所有操作委派给被封装的对象。

    • 具体装饰器 (Concrete Decorators):定义了可动态添加到部件的额外行为。具体装饰类会重写装饰基类的方法,并在调用父类方法之前或之后进行额外的行为。


    4、案例代码

    考虑一个咖啡店的订单系统,我们有不同类型的咖啡(如浓缩咖啡和拿铁咖啡),以及额外的调料(如牛奶和糖)。为了实现灵活性,我们可以使用装饰器模式来动态地为咖啡对象添加调料。


    首先,我们定义抽象构件(Coffee)和具体构件(Espresso和Latte):

    // 抽象构件 - 咖啡
    interface Coffee {
        String getDescription();
        double getCost();
    }
    
    // 具体构件 - 浓缩咖啡
    class Espresso implements Coffee {
        @Override
        public String getDescription() {
            return "浓缩咖啡";
        }
    
        @Override
        public double getCost() {
            return 2.0;
        }
    }
    
    // 具体构件 - 拿铁咖啡
    class Latte implements Coffee {
        @Override
        public String getDescription() {
            return "拿铁咖啡";
        }
    
        @Override
        public double getCost() {
            return 3.0;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    然后,我们定义基础装饰器类(CoffeeDecorator)和具体装饰器类(MilkDecorator和SugarDecorator):

    // 装饰器 - 咖啡装饰器
    abstract class CoffeeDecorator implements Coffee {
        protected Coffee coffee;
    
        public CoffeeDecorator(Coffee coffee) {
            this.coffee = coffee;
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription();
        }
    
        @Override
        public double getCost() {
            return coffee.getCost();
        }
    }
    
    // 具体装饰器 - 牛奶装饰器
    class MilkDecorator extends CoffeeDecorator {
        public MilkDecorator(Coffee coffee) {
            super(coffee);
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription() + ",加牛奶";
        }
    
        @Override
        public double getCost() {
            return coffee.getCost() + 0.5;
        }
    }
    
    // 具体装饰器 - 糖装饰器
    class SugarDecorator extends CoffeeDecorator {
        public SugarDecorator(Coffee coffee) {
            super(coffee);
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription() + ",加糖";
        }
    
        @Override
        public double getCost() {
            return coffee.getCost() + 0.2;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    最后,我们可以使用装饰器模式来创建不同类型的咖啡,并动态地添加调料:

    public class Main {
        public static void main(String[] args) {
            // 创建浓缩咖啡
            Coffee espresso = new Espresso();
            System.out.println(espresso.getDescription() + ",价格:" + espresso.getCost());
    
            // 创建拿铁咖啡
            Coffee latte = new Latte();
            System.out.println(latte.getDescription() + ",价格:" + latte.getCost());
    
            // 创建加牛奶的浓缩咖啡
            Coffee espressoWithMilk = new MilkDecorator(new Espresso());
            System.out.println(espressoWithMilk.getDescription() + ",价格:" + espressoWithMilk.getCost());
    
            // 创建加糖的拿铁咖啡
            Coffee latteWithSugar = new SugarDecorator(new Latte());
            System.out.println(latteWithSugar.getDescription() + ",价格:" + latteWithSugar.getCost());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    输出结果:

    浓缩咖啡,价格:2.0
    拿铁咖啡,价格:3.0
    浓缩咖啡,加牛奶,价格:2.5
    拿铁咖啡,加糖,价格:3.2
    
    • 1
    • 2
    • 3
    • 4

    通过装饰器模式,我们可以动态地为咖啡对象添加不同的调料,而不需要修改原始的咖啡类。这种灵活性使得我们能够轻松地创建各种组合,并且可以随时添加或删除调料。


    然而,装饰器模式并不仅限于咖啡店的订单系统。它在许多其他领域中都有广泛的应用,例如图形用户界面(GUI)框架、输入输出流处理等。在后续的博文中,我们将深入探讨装饰器模式的更多应用场景和技巧,让我们拭目以待!


    敬请期待我们下一篇博文,将为您揭开更多关于装饰器模式的神秘面纱。


    好了,今天的分享到此结束。如果觉得我的博文帮到了您,您的点赞和关注是对我最大的支持。如遇到什么问题,可评论区留言。


  • 相关阅读:
    vscode编写前端提升效率的三个必不可缺的插件以及使用方法
    微软开源 windows-drivers-rs,用 Rust 开发 Windows 驱动程序
    【工具推荐】KeePass安装与插件推荐
    23、Android -- OKHttp3 基础学习
    px转rem插件postcss-plugin-px2rem使用方法(浏览器缩放页面自适应)
    Mybatis -- 使用
    创建镜像发布到镜像仓库【不依赖docker环境】
    shell编程
    Java安装教程:如何安装java环境?
    Python数据分析与机器学习32-聚类算法
  • 原文地址:https://blog.csdn.net/lizhong2008/article/details/134225579