装饰器模式:灵活扩展功能的设计利器

news2024/12/23 3:04:54

装饰器模式是一种结构型设计模式,它允许我们在不改变现有对象结构的情况下,动态地将新功能附加到对象上。本文将深入探讨装饰器模式的原理、结构和使用方法,并通过详细的 Java 示例代码来说明。

1. 装饰器模式的定义

装饰器模式是一种允许我们向现有对象动态添加功能的设计模式,同时又不改变其结构。它通过创建一个装饰器类,该类包装了原始对象,并在保持接口不变的情况下,提供了额外的功能。

2. 装饰器模式的结构

装饰器模式包含以下几个核心角色:

  • 组件(Component):定义了原始对象和装饰器对象的共同接口,可以是抽象类或接口。它定义了被装饰对象的行为。
  • 具体组件(Concrete Component):表示原始对象,它实现了组件接口,并提供了基本的功能。
  • 装饰器(Decorator):继承或实现了组件接口,并持有一个组件对象的引用。它可以在调用组件对象之前或之后添加额外的功能。
  • 具体装饰器(Concrete Decorator):表示具体的装饰器对象,它扩展了装饰器类,并提供了具体的功能扩展。

下图展示了装饰器模式的结构:

3. 装饰器模式的工作原理

装饰器模式的工作原理可以简述如下:

  1. 定义组件接口,包含原始对象和装饰器对象的共同操作。
  2. 创建具体组件类,实现组件接口的方法,提供基本功能。
  3. 创建装饰器类,继承或实现组件接口,并持有一个组件对象的引用。在装饰器类中,调用组件对象的方法,并在其前后添加额外的功能。
  4. 创建具体装饰器类,扩展装饰器类,并提供具体的功能扩展。
  5. 在客户端中,使用装饰器模式,通过组件接口操作装饰后的对象。

4. Java 示例代码

下面通过一个简单的 Java 示例代码来演示装饰器模式的使用。

首先,我们定义组件接口 Component,其中包含了原始对象和装饰器对象的共同操作:

public interface Component {
    void operation();
}

然后,我们创建具体组件类 ConcreteComponent,实现了组件接口的方法,提供基本功能:

public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("执行基本操作");
    }
}

接下来,我们创建装饰器类 Decorator,继承或实现组件接口,并持有一个组件对象的引用。在装饰器类中,调用组件对象的方法,并在其前后添加额外的功能:

public abstract class Decorator implements Component {
    protected Component component;

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

    @Override
    public void operation() {
        component.operation();
    }
}

然后,我们创建具体装饰器类 ConcreteDecorator,扩展装饰器类,并提供具体的功能扩展:

public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("执行额外操作1");
        super.operation();
        System.out.println("执行额外操作2");
    }
}

最后,我们在客户端中使用装饰器模式,通过组件接口操作装饰后的对象:

public class Client {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        component.operation();

        System.out.println("------");

        Component decoratedComponent = new ConcreteDecorator(component);
        decoratedComponent.operation();
    }
}

输出结果为:

执行基本操作
------
执行额外操作1
执行基本操作
执行额外操作2

从输出结果可以看出,通过装饰器模式,我们成功地在不改变原始对象结构的情况下,动态地添加了额外的功能。

5. 装饰器模式的优点和适用场景

装饰器模式具有以下优点:

  • 灵活性:装饰器模式允许我们动态地添加或删除对象的功能,使得功能扩展更加灵活。
  • 遵循开闭原则:装饰器模式遵循开闭原则,使得我们可以在不修改现有代码的情况下,扩展对象的功能。
  • 细粒度控制:装饰器模式允许我们对对象的功能进行细粒度的控制,可以选择性地添加或删除功能。

装饰器模式适用于以下场景:

  • 需要动态地为对象添加额外功能的场景,而且这些功能可以灵活组合。
  • 需要对对象的功能进行细粒度的控制,以满足特定需求。
  • 需要在不改变现有对象结构的情况下,扩展对象的功能。

6. 总结

装饰器模式是一种允许我们动态地为对象添加功能的设计模式,同时又不改变其结构。通过装饰器模式,我们可以灵活地扩展对象的功能,并且遵循开闭原则。装饰器模式适用于需要动态地添加功能、细粒度控制对象功能的场景。

公众号请关注"果酱桑", 一起学习,一起进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/746124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python: 如何批量预处理FY4A L1 DISK和REGC产品?(辐射定标/裁剪/GLT校正/HDF5转TIFF文件等)

目录 01 前言 1.1 想要说 1.2 Requirements 1.3 程序适用数据集 02 函数说明 2.1 读取HDF5文件某一数据集 2.2 读取HDF5文件数据集属性 2.3 对FY4A数据集进行辐射定标 2.4 基于官方地理对照表获取经纬度数据(仅适用DISK) 2.5 依据行列号计算经纬度数据(仅适用DISK) …

C++primer(第五版)第十八章(用于大型程序的工具)

不做大项目的话估计下面的都暂时用不到,包括下一章 大规模应用程序要求:能使用各种库进行协调开发(多人多文件编程);能在独立开发的子系统之间协同处理错误(说人话就是我用了你写的库结果报错了,我们得协调处理好出错的地方);能对比较复杂的应用概念进行建模(定义合理的类,函数…

(工具记录)Log4j2_RCE

0x00 简介 ApacheLog4j2是一个开源的Java日志框架,被广泛地应用在中间件、开发框架与Web应用中。 0x01 漏洞概述 该漏洞是由于Apache Log4j2某些功能存在递归解析功能,未经身份验证的攻击者通过发送特定恶意数据包,可在目标服务器上执行任意…

获取DNF人物坐标值

众所周知DNF是一个没有坐标值显示的游戏。 那么如何才能不碰内存和封包的情况下,获取DNF游戏中人物在当前房间的坐标值呢? 有兴趣的找我交流吧。

Go语言IO模式

Go语言IO模式 IO 操作是我们在编程中不可避免会遇到的,Go语言的 io 包中提供了相关的接口,定义了相应的规范,不同的数 据类型可以根据规范去实现相应的方法,提供更加丰富的功能。 本文主要介绍常见的 IO (输入和输出)模式&…

《MySQL》复合查询和连接

文章目录 查询单行子查询多行子查询合并查询 连接内连接外连接 点睛之笔:无论是多表还是单表,我们都可以认为只有一张表。 只要是表,就可以查询和连接成新表,所以select出来的结果都可以认为成一张表,既然是一张表&…

Python多线程使用详解

概要 多线程是一种并发编程的技术,通过同时执行多个线程来提高程序的性能和效率。在Python中,我们可以使用内置的threading模块来实现多线程编程。 一、创建线程 在使用多线程之前,我们首先需要了解如何创建线程。Python提供了threading模块…

你信不信,只要学几天javascript就可以使用纯原生实现五星评分效果 【附完整代码】

🚀 个人主页 极客小俊 ✍🏻 作者简介:web开发者、设计师、技术分享博主 🐋 希望大家多多支持一下, 我们一起进步!😄 🏅 如果文章对你有帮助的话,欢迎评论 💬点赞&#x1…

动态规划DP(七) 股票交易

1.股票交易 在股票买卖的最佳时机问题中,给定一个数组,数组中的每个元素代表某一天的股票价格。你可以进行多次买入和卖出,但是必须在再次购买前卖出之前的股票。目标是找到最大的利润。 动态规划可以用于解决股票交易类的问题,…

ssl证书和域名过期提醒平台

由于经常忘记了证书是否要过期,导致过期了出现一些访问上的问题 docker安装部署 当然可以接入mysql,默认使用的sqlite version: "3" services:domain-admin:image: mouday/domain-admin:latestcontainer_name: domain-adminvolumes:- ./data:/…

菜鸡shader:L8 UV扰动动画——火焰和简单水面

文章目录 卡通火焰代码最后效果 水面代码最后效果 这此做笔记的两个shader其实是课程的作业,课程主要也是讲UV扰动的概念,因为课程的shader在另一台电脑上,做笔记就暂时不带他们了,简单做下火焰和水面的shader。 卡通火焰 火焰这…

FreeRTOS(队列)

队列 什么是队列? 队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任 务间传递信息。 为什么不使用全局变量? 如果使用全局变量,兔子(任务1)修改了变量 a …

新版studio没法筛选Log

目录 方式一 简单粗暴,针对怀旧者,可切回原版log视图 方式二 学习新的log过滤方法 升级新版本AndroidStudio后,log日志变成以下样子,发现之前过滤error,infor的tab都不见了,瞬间不淡定了,查阅资料才发现…

DAY45:动态规划(五)背包问题:01背包理论基础+二维DP解决01背包问题

文章目录 背包问题大纲01背包01背包暴力解法01背包二维DP解法二维DP数组的解法DP数组含义递推公式初始化二维DP数组(比较重要)遍历顺序(比较重要) 二维DP数组完整版思路总结返回值为什么是二维数组最后一个元素DP推导过程与数组含…

selenium 根据期刊信息获取知网文献信息 pt.1

哈喽大家好,我是咸鱼 之前写过一篇获取知网文献信息的文章,看了下后台数据还挺不错 所以咸鱼决定再写一篇知网文献信息爬取的文章 需要注意的是文章只是针对某一特定期刊的爬取,希望小伙伴们把关注点放在如何分析网页以及如何定位元素上面…

python实现前后端学生管理系统(前后端不分离)

⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐作者主页:逐梦苍穹 ⭐所属专栏:项目。 目录 1、前言2、简述实现内容首页注册登录管理员 3、详细代码3.1、项目目录3.2、templates3.2.1、testxz…

赛效:如何在线转换图片格式

1:点击左侧菜单栏里的“格式转换”,然后在转换格式菜单栏里点击上传按钮。 2:选择下方输出格式,点击右下角“开始转换”。 3:稍等片刻转换成功后,点击图片右下角的“下载”,将转换后的图片保存到…

UE5《Electric Dreams》项目PCG技术解析 之 PCGCustomNodes详解(四)ApplyHierarchy

继续解析《Electric Dreams》项目中的自定义节点和子图:ApplyHierarchy 文章目录 前导文章标准组合拳ApplyHierarchyExecute with ContextIteration Loop BodyPoint Loop Body应用场景 小结 前导文章 《UE5《Electric Dreams》项目PCG技术解析 之 理解Assembly&…

【Android】APT与JavaPoet学习与实战

PS:本文讲解的APT全称为Annotation Processing Tool,而非是Android Performance Tuner,这两种工具简称皆为APT,前者是“注释处理工具”,后者是“Android性能调试器”。 本文分别使用Java、kotlin 语言进行开发&#xf…

做一个游戏小项目有多简单?

认识一个朋友,学了很多年的 python, 还停留在 helloworld 阶段,每次拿起又放下,是不是很熟悉?每天都在想,我要学编程,我要学编程,但是又不知道从何学起,学了一点又不知道怎么用&…