「聊设计模式」之装饰器模式(Decorator)

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


前言

设计模式是面向对象编程中的重要概念,它是一种解决特定问题的经过验证的方法。设计模式可以提高代码的复用性、可读性、可维护性和可扩展性。其中,装饰器模式是一种常见的结构型模式。

摘要

装饰器模式是指在不改变原有对象的基础上,通过对其进行包装拓展,使其具有更强的功能。它在不改变原有代码的基础上,通过添加一些新的功能来满足用户的需求。

装饰器模式

概念

装饰器模式(Decorator)是一种结构型设计模式,它允许我们在运行时扩展一个对象的功能,而不需要修改它的结构。

在装饰器模式中,我们创建一个装饰器类,该类实现一个与被装饰对象相同的接口,并且通过将被装饰对象作为参数传递到装饰器中,实现对被装饰对象的包装。这使得我们可以在不修改原始对象的基础上,在运行时动态地添加或删除对象的功能。

装饰器模式的主要优点是它提供了一种灵活的方式来扩展对象的功能,而不需要修改其结构或代码。此外,它也允许我们避免创建大量的子类来实现对象的不同功能。

装饰器模式的一些常见应用包括:为对象添加缓存、日志记录、安全验证、性能优化等功能。

结构

装饰器模式包含以下关键元素:

  1. Component(组件):定义装饰器和被装饰器的共同接口,即原始对象的接口。

  2. Concrete Component(具体组件):实现Component接口的具体对象,即被装饰器的原始对象。

  3. Decorator(装饰器):实现Component接口,并包含一个Component类型的成员变量,即被装饰器对象,用于给对象添加新功能。

  4. Concrete Decorator(具体装饰器):实现Decorator接口的具体类,用于给被装饰器对象添加新的行为。

如下是装饰器模式的UML类图:

模式演示

我们以Java开发语言为例来讲解装饰器模式。在这里,我们定义一个接口Component,它有一个方法operation(),用于返回一个字符串。然后,我们定义一个类ConcreteComponent,它实现了Component接口,并重写了operation()方法。最后,我们定义一个抽象类Decorator,它也实现了Component接口,并重写了operation()方法。

Component接口

java 复制代码
package com.example.javaDesignPattern.decorator;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:48
 */
public interface Component {
    public String operation();
}

ConcreteComponent类

java 复制代码
package com.example.javaDesignPattern.decorator;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:50
 */
public class ConcreteComponent implements Component {
    @Override
    public String operation() {
        return "ConcreteComponent";
    }
}

Decorator抽象类

java 复制代码
package com.example.javaDesignPattern.decorator;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:50
 */
public abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public String operation() {
        return component.operation();
    }
}

在这里,我们定义了一个抽象类Decorator,它有一个Component成员变量,并在构造函数中进行初始化。Decorator类重写了Component接口中的operation()方法,该方法返回成员变量componentoperation()方法的返回值。

接下来,我们可以定义一些具体的装饰器类,它们继承自Decorator类,并在构造函数中调用父类的构造函数。这些具体的装饰器类可以增加一些新的功能,比如说添加一个字符串"DecoratorA"等。下面是一个具体的装饰器类DecoratorA

java 复制代码
package com.example.javaDesignPattern.decorator;

/**
 * 具体的装饰器类DecoratorA
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:50
 */
public class DecoratorA extends Decorator {
    public DecoratorA(Component component) {
        super(component);
    }

    @Override
    public String operation() {
        return "DecoratorA " + component.operation();
    }
}

DecoratorA类中,我们重写了operation()方法,并在其中添加了一个字符串"DecoratorA "。同时,我们调用了父类的构造函数,使其具有Decorator类的特性。

测试用例

我们可以编写一个测试类DecoratorTest,用于测试装饰器模式的实现。在这个测试类中,我们先创建一个ConcreteComponent对象,然后用DecoratorA对其进行包装装饰,并调用operation()方法输出结果。下面是测试代码的完整实现:

java 复制代码
package com.example.javaDesignPattern.decorator;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:51
 */
public class DecoratorTest {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratedComponent = new DecoratorA(component);
        System.out.println(decoratedComponent.operation());
    }
}

在这个测试类中,我们创建了一个ConcreteComponent对象,并将其传递给DecoratorA类的构造函数中。最后,我们调用了DecoratedComponent对象的operation()方法,并输出了结果。

运行结果

执行结果如下:

当我们运行DecoratorTest类时,可以看到控制台输出了"DecoratorA ConcreteComponent"的字符串。这说明我们成功地实现了装饰器模式。

代码解析

首先定义了一个抽象组件(Component)接口,它有一个操作方法operation()

接着定义了具体组件(ConcreteComponent)类,实现了抽象组件接口,并实现了operation()方法。

然后定义了装饰器(Decorator)类,也是实现了抽象组件接口,并包含了一个抽象组件对象作为成员变量,用于装饰(增强)抽象组件对象的操作方法。

最后定义了具体装饰器A(DecoratorA)类,它继承了装饰器类,并实现了其对抽象组件对象的具体装饰行为。

main函数中,首先创建了一个具体组件对象,然后创建了一个具体装饰器A对象,用于装饰具体组件对象,最后调用了装饰后的组件对象的操作方法。

此时,输出的结果就是具体装饰器A对具体组件对象操作后的结果。

小结

在本篇文章中,我们详细介绍了装饰器模式的概念及其实现方式。装饰器模式可以为现有对象添加一些新的功能,而不需要修改原有的代码。这种设计模式可以提高代码的可读性、可维护性和可扩展性,因此在实际开发中得到了广泛的应用。

附录源码

如上涉及代码均已上传同步在 GitHub,提供给同学们参考性学习。

总结

在本篇文章中,我们讲解了装饰器模式的实现方式及其应用场景。在实际开发中,装饰器模式可以为现有对象添加一些新的功能,而不需要修改原有的代码。这种设计模式可以提高代码的可读性、可维护性和可扩展性,因此在实际开发中得到了广泛的应用。同时,在编写代码时,我们也需要注意装饰器类的数量,不能过多地添加,否则会导致代码的臃肿和复杂度的提高。

☀️建议/推荐你

如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

📣关于我


我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

相关推荐
小灰灰__12 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭15 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果36 分钟前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
追风林41 分钟前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨1 小时前
El表达式和JSTL
java·el
许野平1 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
duration~2 小时前
Maven随笔
java·maven
zmgst2 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD2 小时前
前后端分离,Jackson,Long精度丢失
java
blammmp2 小时前
Java:数据结构-枚举
java·开发语言·数据结构