技术成神之路:设计模式(二十)装饰模式
介绍
装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变对象自身的情况下,动态地为对象添加额外的职责。这个模式通常用于增强或改变对象的功能。
1.定义
装饰模式通过创建一个装饰类,将功能动态地添加到被装饰类的实例中。装饰类与被装饰类实现相同的接口或继承相同的父类,这样装饰对象就可以取代被装饰对象。
2. 主要作用
- 动态地给一个对象添加额外的职责,而不改变其原本的结构。
- 提供了比继承更灵活的替代方案,通过组合而不是继承来扩展对象的功能。
3. 解决的问题
- 需要在运行时为对象动态添加功能,而不修改对象本身。
- 需要避免因类数量过多而导致的复杂性。
- 需要在不影响其他对象的情况下扩展功能。
4. 模式原理
包含角色:
- 组件接口(Component): 定义了一个接口,用于所有具体组件和装饰器。
- 具体组件(ConcreteComponent): 实现了组件接口的具体类。
- 装饰器(Decorator): 实现了组件接口并持有一个组件的引用,用于在其方法中调用被装饰对象的方法。
- 具体装饰器(ConcreteDecorator): 继承自装饰器类,添加额外的功能。
UML类图:
代码示例:
// Component接口
public interface Coffee {double cost();String description();
}// ConcreteComponent具体组件
public class SimpleCoffee implements Coffee {@Overridepublic double cost() {return 5;}@Overridepublic String description() {return "Simple Coffee";}
}// Decorator装饰器
public abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}@Overridepublic double cost() {return decoratedCoffee.cost();}@Overridepublic String description() {return decoratedCoffee.description();}
}// ConcreteDecorator具体装饰器
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic double cost() {return super.cost() + 1.5;}@Overridepublic String description() {return super.description() + ", Milk";}
}public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic double cost() {return super.cost() + 0.5;}@Overridepublic String description() {return super.description() + ", Sugar";}
}
调用
public class DecoratorPatternExample {public static void main(String[] args) {Coffee simpleCoffee = new SimpleCoffee();System.out.println(simpleCoffee.description() + " $" + simpleCoffee.cost());Coffee milkCoffee = new MilkDecorator(simpleCoffee);System.out.println(milkCoffee.description() + " $" + milkCoffee.cost());Coffee milkSugarCoffee = new SugarDecorator(milkCoffee);System.out.println(milkSugarCoffee.description() + " $" + milkSugarCoffee.cost());}
}
打印输出
Simple Coffee \$5.0
Simple Coffee, Milk \$6.5
Simple Coffee, Milk, Sugar \$7.0
上面示例,通过使用装饰者模式,程序能够灵活地添加新功能而不需要修改原有的 Coffee 实现。
装饰模式看似很简单,其实一点也不复杂😁,我相信看完一遍示例,再回头看下定义就会全懂了。
那么看似一个简单的设计模式,在我们开发中有哪些应用场景呢?下面举几个经典示例来加深下印象:
1.Java的输入/输出(I/O)库中使用了装饰者模式来增强流的功能。
例如,BufferedInputStream
和 DataInputStream
是装饰者,它们分别装饰 InputStream
类。通过这些装饰者,可以为基础流添加缓冲、数据格式等额外的功能。
emm… 上一篇文章,桥接模式也是举的这个例子,看来Java SDK使用的设计模式不少啊。
InputStream fileStream = new FileInputStream("file.txt");
BufferedInputStream bufferedStream = new BufferedInputStream(fileStream);
DataInputStream dataStream = new DataInputStream(bufferedStream);
2.Android View 组件
安卓开发的同学肯定都自定义过View
吧,例如,创建一个自定义的TextView
,通过扩展原始的TextView
并添加一些额外的样式或功能。
public class CustomTextView extends TextView {public CustomTextView(Context context) {super(context);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 添加自定义绘制逻辑}
}
还有在 使用 Retrofit
网络请求时,可以自定义的拦截器,Spring
框架的 AOP
通过代理(proxy)对象,可以在不改变原始对象的情况下,动态地添加横切关注点(如日志记录、事务管理等)等等… 这些都是装饰模式的经典案例。可能我们平时没注意,不知道它们用的是装饰模式,只要记住只要是 在运行时动态地添加行为和功能就可以认为是装饰者模式即可。
5. 优缺点
优点:
- 灵活性:可以动态地添加或修改对象的功能,而无需修改原始类。
- 扩展性:可以通过添加新的装饰器类来扩展功能,不需要改变现有代码。
- 符合开闭原则:原有类不需要改变,新增功能通过装饰器实现。
缺点:
- 复杂性:使用装饰模式会增加系统的复杂性,特别是在多个装饰器层叠使用时。
- 调试困难:由于装饰者的层级结构,调试时可能不容易追踪到具体的功能实现。
6. 应用场景
- 在图形界面中,可以为组件如按钮、文本框等添加滚动条、边框等装饰。
- 在Java的IO系统中,装饰模式被广泛应用于各种输入流和输出流的实现中,如BufferedInputStream装饰FileInputStream。
- 需要在不改变原有类的情况下,动态地为对象添加功能。
7. 总结
装饰模式是一种强大的设计模式,通过组合对象和装饰器的方式实现功能的动态扩展。它在实际开发中非常有用,能够有效地提高代码的灵活性和可维护性。虽然引入了额外的复杂性,但在许多情况下,这种复杂性是值得的,因为它使得系统可以更容易地适应变化和需求。
相关文章:

技术成神之路:设计模式(二十)装饰模式
介绍 装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变对象自身的情况下,动态地为对象添加额外的职责。这个模式通常用于增强或改变对象的功能。 1.定义 装饰模式通过创建一个装饰类,将功能动态地添加…...

利用特征点采样一致性改进icp算法点云配准方法
1、index、vector 2、kdtree和kdtreeflann 3、if kdtree.radiusSearch(。。。) > 0)...

LabVIEW惯性导航系统仿真平台
LabVIEW开发捷联惯性导航系统仿真平台,采用模块化设计,利用LabVIEW的图形化编程特性,提高了系统仿真的效率和精度,同时具备良好的可扩展性和用户交互性。 项目背景 当前,惯性导航系统(INS)的研…...
es简单实现文章检索功能
使用的api是:Elasticsearch Java API client 8.0 官网:Package structure and namespace clients | Elasticsearch Java API Client [8.15] | Elastic 1.建立索引库 实现搜索功能字段: title:文章标题content:文章内…...

太速科技-607-基于FMC的12收和12发的光纤子卡
基于FMC的12收和12发的光纤子卡 一、板卡概述 本卡是一个FPGA夹层卡(FMC)模块,可提供高达2个CXP模块接口,提供12路收,12路发的光纤通道。每个通道支持10Gbps,通过Aurora协议,可以组成X4࿰…...

UEFI学习笔记(十):系统表与ACPI表的遍历
一、概述 在 UEFI 系统表中,有几个关键的表用于提供系统信息、服务和硬件抽象。这些表可以通过 EFI_SYSTEM_TABLE 访问,常见的 UEFI 系统表如下: 1、EFI_SYSTEM_TABLE (系统表) EFI_SYSTEM_TABLE 是一个指针,包含多个服务和系统…...

【深度学习基础模型】液态状态机(Liquid State Machines, LSM)详细理解并附实现代码。
【深度学习基础模型】液态状态机(Liquid State Machines, LSM)详细理解并附实现代码。 【深度学习基础模型】液态状态机(Liquid State Machines, LSM)详细理解并附实现代码。 文章目录 【深度学习基础模型】液态状态机࿰…...

深入理解链表(SList)操作
目录: 一、 链表介绍1.1、 为什么引入链表1.2、 链表的概念及结构1.3、 链表的分类 二、 无头单向非[循环链表](https://so.csdn.net/so/search?q循环链表&spm1001.2101.3001.7020)的实现2.1、 [单链表](https://so.csdn.net/so/search?q单链表&spm1001.2…...
03. prometheus 监控 Linux 主机
文章目录 一、prometheus 监控 Linux 主机二、防火墙打开端口1. 方式一:使用 iptables 添加白名单(推荐使用):2. 方式二:重载防火墙 一、prometheus 监控 Linux 主机 1. 官网下载 node_exporter 官网:htt…...

AI占据2024诺贝尔两大奖项,是否预示着未来AI即一切?
本次诺贝尔物理学和学奖的获得者都与AI息息相关,可谓是“AI领域的大丰收”。 2024年诺贝尔物理学奖揭晓:瑞典皇家科学院公布了2024年诺贝尔物理学奖的获得者。他们是美国的约翰霍普菲尔德(John J. Hopfield),以及加拿…...

[已解决] Install PyTorch 报错 —— OpenOccupancy 配环境
目录 关于 常见的初始化报错 环境推荐 torch, torchvision & torchaudio cudatoolkit 本地pip安装方法 关于 OpenOccupancy: 语义占用感知对于自动驾驶至关重要,因为自动驾驶汽车需要对3D城市结构进行细粒度感知。然而,现有的相关基准在城市场…...

6. PH47 代码框架硬件开发环境搭建
概述 PH47代码框架的硬件开发环境搭建同样简单, 建立基本的 PH47 框架学习或二次开发的硬件开发环境所需设备如下: BBP 飞控板及相关软硬件: BBP飞控板,或者至少一块Stm32F411核心板(WeAct Studio)Stm32程序烧录工具…...
package.json配置
package.json配置 描述配置文件配置脚本配置依赖配置发布配置系统配置第三方配置 描述配置 name : 项目名称,第三方包可以通过npm install 包名安装 "name":"react"version : 项目版本,项目版本号 "version" : "18.2…...

视频怎么转gif动图?5个简单转换方法快来学(详细教程)
相信大家在社交平台上会经常看到一些有趣的gif动图表情包,有些小伙伴就会问:这些GIF动图是如何制作的呢?一般GIF动图表情包可以用视频来制作,今天小编就来给大家分享几个视频转成GIF动图的方法,相信通过以下的几个方法…...

10月更新:优维EasyOps®需求解决更彻底,功能体验再升级
升 级 不 止 步 欢迎来到 需求至上,功能完善 的 \ EasyOps 7.5版本 / 👇 >> 联动架构视图:深度融合监控与资源拓扑 传统上,依赖监控态势感知系统固有的分层拓扑结构虽有其优势,但在处理复杂系统尤其是核心数…...
黑马javaWeb笔记重点备份1:三层架构、IOC、DI
来自:【黑马程序员JavaWeb开发教程,实现javaweb企业开发全流程(涵盖SpringMyBatisSpringMVCSpringBoot等)】 https://www.bilibili.com/video/BV1m84y1w7Tb/?p75&share_sourcecopy_web&vd_source9332b8fc5ea8d349a54c398…...

大坝渗流监测设备——渗压计
渗压计是一种用于监测大坝等水工建筑物渗流压力的重要设备,其准确性和可靠性对于保障大坝安全运行至关重要。南京峟思将为大家详细介绍渗压计的工作原理、安装方法及其在大坝渗流监测中的应用。 渗压计主要利用振弦频率的变化来测量渗透水压力。设备由透水部件、感应…...

Pikachu-Sql Inject-宽字节注入
基本概念 宽字节是相对于ascII这样单字节而言的;像 GB2312、GBK、GB18030、BIG5、Shift_JIS 等这些都是常说的宽字节,实际上只有两字节 GBK 是一种多字符的编码,通常来说,一个 gbk 编码汉字,占用2个字节。一个…...

如何制作低代码开发的视频教程?
如何制作低代码开发的视频教程? 随着数字化转型的加速,越来越多的企业和组织开始采用低代码开发平台来加速应用程序的构建。对于许多开发者和业务人员来说,学习如何使用这些平台可以显著提高工作效率。因此,创建一份清晰、实用且…...
Flink学习地址
--基础概念 概览 | Apache Flink --应用系列 如何学习Flink:糙快猛的大数据之路(图文并茂)_flink 学习-CSDN博客 --Python系列 pyflink实时接收kafka数据至hive_pyflink下kafka数据经过处理后插入hive-CSDN博客 Pyflink教程(一)&#…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

李沐--动手学深度学习--GRU
1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...