当前位置: 首页 > news >正文

技术成神之路:设计模式(二十)装饰模式

介绍

装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变对象自身的情况下,动态地为对象添加额外的职责。这个模式通常用于增强或改变对象的功能。

1.定义


装饰模式通过创建一个装饰类,将功能动态地添加到被装饰类的实例中。装饰类与被装饰类实现相同的接口或继承相同的父类,这样装饰对象就可以取代被装饰对象。

2. 主要作用


  • 动态地给一个对象添加额外的职责,而不改变其原本的结构。
  • 提供了比继承更灵活的替代方案,通过组合而不是继承来扩展对象的功能。

3. 解决的问题


  • 需要在运行时为对象动态添加功能,而不修改对象本身。
  • 需要避免因类数量过多而导致的复杂性。
  • 需要在不影响其他对象的情况下扩展功能。

4. 模式原理


包含角色:

  1. 组件接口(Component): 定义了一个接口,用于所有具体组件和装饰器。
  2. 具体组件(ConcreteComponent): 实现了组件接口的具体类。
  3. 装饰器(Decorator): 实现了组件接口并持有一个组件的引用,用于在其方法中调用被装饰对象的方法。
  4. 具体装饰器(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)库中使用了装饰者模式来增强流的功能。
例如,BufferedInputStreamDataInputStream 是装饰者,它们分别装饰 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&#xff0…...

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)详细理解并附实现代码。 文章目录 【深度学习基础模型】液态状态机&#xff0…...

深入理解链表(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教程(一)&#…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言: 类加载器 1. …...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...