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

Java设计模式之装饰器(Decorator)模式

装饰器(Decorator)设计模式允许动态地将新功能添加到对象中,同时又不改变其结构。

什么是装饰器模式

装饰器(Decorator)模式通过将对象进行包装,以扩展其功能,而不需要修改其原始类。装饰器模式基于组合而非继承的原则,通过递归和委托来创建具有新功能的对象。

装饰器模式的使用场景

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

  • 需要在运行时为对象添加额外的行为,而不影响其他对象。
  • 需要动态地为对象添加新的功能,而又不希望生成大量的子类。

装饰器模式的代码示例

下面是一个简单的示例,我们将使用装饰器模式来扩展一个咖啡店中的咖啡品种,如添加牛奶、糖等。我们将创建一个基础的咖啡接口,然后使用装饰器类来扩展可选的配料。下面是代码实现:

// 咖啡接口
interface Coffee {String getIngredients(); // 获取咖啡配料double getPrice(); // 获取咖啡价格
}// 基础咖啡类
class SimpleCoffee implements Coffee {public String getIngredients() {return "Coffee";}public double getPrice() {return 2.0;}
}// 咖啡装饰器基类
abstract class CoffeeDecorator implements Coffee {protected Coffee coffee;public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}public String getIngredients() {return coffee.getIngredients();}public double getPrice() {return coffee.getPrice();}
}// 牛奶咖啡装饰器
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}public String getIngredients() {return coffee.getIngredients() + ", Milk";}public double getPrice() {return coffee.getPrice() + 0.5;}
}// 糖咖啡装饰器
class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}public String getIngredients() {return coffee.getIngredients() + ", Sugar";}public double getPrice() {return coffee.getPrice() + 0.3;}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建基础咖啡对象Coffee baseCoffee = new SimpleCoffee();System.out.println("基础咖啡: " + baseCoffee.getIngredients() + ", 价格: " + baseCoffee.getPrice());// 添加牛奶Coffee milkCoffee = new MilkDecorator(baseCoffee);System.out.println("加入牛奶: " + milkCoffee.getIngredients() + ", 价格: " + milkCoffee.getPrice());// 添加糖Coffee sugarCoffee = new SugarDecorator(milkCoffee);System.out.println("加入糖: " + sugarCoffee.getIngredients() + ", 价格: " + sugarCoffee.getPrice());}
}

在上述代码中,我们定义了一个咖啡接口(Coffee),以及一个基础咖啡类(SimpleCoffee)实现了这个接口。然后,我们创建了一个咖啡装饰器基类(CoffeeDecorator),它也实现了咖啡接口,并通过构造函数接收一个咖啡对象。接下来,我们创建了两个具体的装饰器类:牛奶装饰器(MilkDecorator)和糖装饰器(SugarDecorator),它们都继承自咖啡装饰器基类,并分别扩展了咖啡的配料和价格。

最后,在客户端代码中,我们实例化了一个基础咖啡对象,然后使用装饰器类将其包装,以便于在咖啡中添加牛奶和糖。我们可以通过调用装饰器对象的 getIngredients() 和 getPrice() 方法来获取装饰后的咖啡的配料和价格。

运行上述代码,您应该会得到以下输出结果:

基础咖啡: Coffee, 价格: 2.0
加入牛奶: Coffee, Milk, 价格: 2.5
加入糖: Coffee, Milk, Sugar, 价格: 2.8

这是因为我们创建了一个基础咖啡对象,并使用装饰器对象依次包装它,以扩展咖啡的配料和价格。

装饰器模式的具体应用

  1. Java IO:Java的输入输出流(IO)框架使用了装饰器模式。InputStream和OutputStream是抽象基类,而具体的输入输出流类如FileInputStream、ByteArrayInputStream等都是装饰器类的子类。这种设计允许对输入输出流进行递归式的装饰,以扩展其功能和行为。

  2. Spring框架:Spring框架中的AOP(面向切面编程)功能使用了装饰器模式。通过在运行时使用动态代理,它可以在方法调用前后插入额外的行为,如日志记录、性能监控等。

  3. Servlet过滤器:Java Servlet中的过滤器功能使用了装饰器模式。Servlet过滤器可以在请求到达Servlet之前或者响应返回给客户端之前,对请求和响应进行处理和修改。

  4. Guava库:Google的Guava库中的许多工具类和方法使用了装饰器模式。例如,Guava的Collections类提供了许多静态方法对集合进行装饰,如unmodifiableCollection、synchronizedCollection等。

总结

装饰器(Decorator)模式是一种结构型设计模式,它允许动态地将新功能添加到对象中,同时又不改变其结构。装饰器模式基于组合而非继承原则,通过递归和委托来创建具有新功能的对象。装饰器模式适用于需要在运行时扩展对象功能的情况,而不希望生成大量的子类。在实际开发中,我们可以利用装饰器模式来为现有的类或框架添加额外的功能,同时保持代码的灵活性和可维护性。

关注微信公众号:“小虎哥的技术博客”。我们会定期发布关于Java技术的详尽文章,让您能够深入了解该领域的各种技巧和方法,让我们一起成为更优秀的程序员👩‍💻👨‍💻!

相关文章:

Java设计模式之装饰器(Decorator)模式

装饰器(Decorator)设计模式允许动态地将新功能添加到对象中,同时又不改变其结构。 什么是装饰器模式 装饰器(Decorator)模式通过将对象进行包装,以扩展其功能,而不需要修改其原始类。装饰器模…...

element ui树组件render-content 树节点的内容区的渲染另一种方式

直接上代码吧,不用h的写法。 <el-tree :data"data" node-key"id" default-expand-all :expand-on-click-node"false" :props"defaultProps":render-content"renderContentTree" node-click"handleNodeClick"&g…...

html a标签换行显示

文章目录 用css display属性不用css&#xff0c;可以用<br>标签换行示例 用css display属性 可以使用CSS的display属性来实现多个a标签每行显示一个。 HTML代码&#xff1a; <div class"link-container"><a href"#">Link 1</a>…...

关于Redis-存Long取Integer类型转换错误的问题

背景 最近遇到了两个Redis相关的问题&#xff0c;趁着清明假期&#xff0c;梳理整理。 1.存入Long类型对象&#xff0c;在代码中使用Long类型接收&#xff0c;结果报类型转换错误。 2.String对象的反序列化问题&#xff0c;直接在Redis服务器上新增一个key-value&#xff0c…...

设计模式一:简单工厂模式(Simple Factory Pattern)

简单工厂模式&#xff08;Simple Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一个通用的接口来创建各种不同类型的对象&#xff0c;而无需直接暴露对象的创建逻辑给客户端。 简单工厂的三个重要角色&#xff1a; 工厂类&#xff08;Factory Class&…...

如何利用plotly和geopandas根据美国邮政编码(Zip-Code)绘制美国地图

对于我自己来说&#xff0c;该需求源自于分析Movielens-1m数据集的用户数据&#xff1a; UserID::Gender::Age::Occupation::Zip-code 1::F::1::10::48067 2::M::56::16::70072 3::M::25::15::55117 4::M::45::7::02460 5::M::25::20::55455 6::F::50::9::55117我希望根据Zip-…...

ceph集群搭建

文章目录 理论知识具体操作搭建ceph本地源yum源及ceph的安装配置NTP&#xff08;解决时间同步问题&#xff09;部署ceph自定义crush 理论知识 Ceph是一个分布式存储系统&#xff0c;并且提供了文件、对象、块存储功能。 Ceph集群中重要的守护进程有&#xff1a;Ceph OSD、Cep…...

前端密码加密 —— bcrypt、MD5、SHA-256、盐

&#x1f414; 前期回顾悄悄告诉你&#xff1a;前端如何获取本机IP&#xff0c;轻松一步开启网络探秘之旅_彩色之外的博客-CSDN博客前端获取 本机 IP 教程https://blog.csdn.net/m0_57904695/article/details/131855907?spm1001.2014.3001.5501 在前端密码加密方案中&#xff…...

汽车UDS诊断深度学习专栏

1.英文术语 英文术语翻译Diagnostic诊断Onboard Diagnostic 在线诊断 Offboard Diagnostic离线诊断Unified diagnostic service简称 UDS 2.缩写表 缩写解释ISO国际标准化组织UDSUnified diagnostic service&#xff0c;统一的诊断服务ECU电控单元DTC 诊断故障码 ISO14229UD…...

macOS 下安装brew、nvm

1、brew&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" brew -v 查看版本 示例&#xff1a; 安装jdk brew search jdk 查询可用的jdk版本 brew install openjdk11 安装制定版本jdk 更换源&#xff1…...

【云原生】Kubernetes工作负载-StatefulSet

StatefulSet StatefulSet 是用来管理有状态应用的工作负载 API 对象 StatefulSet 用来管理某 Pod 集合的部署和扩缩&#xff0c; 并为这些 Pod 提供持久存储和持久标识符 和 Deployment 类似&#xff0c; StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同…...

Java:方法的重载

方法重载 为什么需要方法重载 在使用方法的过程中我们可能会遇到以下如同例子的情形&#xff1a; ​ ​ public class method1 {public static void main(String[] args) {int a1 10;int b1 20;double ret1 add(a1, b1);System.out.println("ret1 " ret1);do…...

7.react useCallback与useMemo函数使用与常见问题

react useCallback与useMemo函数使用与常见问题 useCallback返回一个可记忆的函数&#xff0c;useMemo返回一个可记忆的值&#xff0c;useCallback只是useMemo的一种特殊形式。 那么这到底是什么意思呢&#xff1f;实际上我们在父子通信的时候&#xff0c;有可能传递的值是一…...

Sentinel限流中间件

目录 介绍 Sentinel 的特征 Sentinel 的组成 实战使用 简单实例 配置本地控制台 使用可视化ui配置简单流控 配置异步任务限流 使用注解定义限流资源 SpringCloud整合Sentinel 简单整合 并发线程流控 关联模式 整合openFeign使用 介绍 随着微服务的流行&#xff0…...

使用ajax进行前后端交互的方法

使用ajax进行前后端交互的方法&#xff1a;&#xff08;我只测试通了json对象作为参数的方式&#xff0c;其他方式我没有测试通过&#xff09; 1、前端方法&#xff1a; 传参方式&#xff1a;POST 请求类型&#xff1a;json对象 响应类型&#xff1a;json对象 function test() …...

动手学深度学习——线性回归从零开始

生成数据集synthetic_data()读取数据集data_iter()初始化模型参数w, b定义模型&#xff1a;线性回归模型linreg()定义损失函数&#xff1a;均方损失squared_loss()定义优化算法&#xff1a;梯度下降sgd()进行训练&#xff1a;输出损失loss和估计误差 %matplotlib inline impor…...

Redis缓存击穿

Redis缓存击穿是指在使用Redis作为缓存时&#xff0c;某个热点数据过期或不存在&#xff0c;导致大量请求直接打到后端存储系统&#xff08;例如数据库&#xff09;&#xff0c;使得后端系统压力骤增&#xff0c;性能下降的情况。这种情况通常发生在热点数据失效的瞬间。 缓存…...

网络安全(黑客)自学的一些建议

1.选择方向 首先是选择方向的问题&#xff0c;网络安全是一个很宽泛的专业&#xff0c;包含的方向特别多。比如 web安全&#xff0c;系统安全&#xff0c;无线安全 &#xff0c;二进制安全&#xff0c;运维安全&#xff0c;渗透测试&#xff0c;软件安全&#xff0c;IOT安全&a…...

全志F1C200S嵌入式驱动开发(基于usb otg的spi-nor镜像烧入)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 前面既然已经搞定了spi-nor驱动,那么下一步考虑的就是怎么从spi-nor flash上面加载uboot、kernel和rootfs。目前spi-nor就是一块白片,上面肯定什么都没有,那么这个时候,我们要做…...

如何恢复损坏/删除的 Word 文件

有关如何修复不可读的 Microsoft Word 文件或 Rich Text 文件中的文本的分步说明。这些说明有助于从损坏的*.doc、*.docx、*.dot、*.dotx、*.rtf文件&#xff08;任何版本和大小&#xff09;中提取文本&#xff0c;只需单击几下&#xff1a; 从此处下载奇客数据恢复 &#xff…...

单片机通信协议详解:IIC、SPI、UART与CAN对比

1. 单片机通信协议概述在嵌入式系统开发中&#xff0c;单片机的通信能力直接影响着整个系统的架构设计和性能表现。作为一名有着十年嵌入式开发经验的工程师&#xff0c;我经常需要根据项目需求选择合适的通信协议。目前主流的单片机通信方式包括IIC、SPI、UART/USART、CAN等&a…...

如何构建LaTeX-Workshop的自动化测试与持续集成流程:开发者完整指南

如何构建LaTeX-Workshop的自动化测试与持续集成流程&#xff1a;开发者完整指南 【免费下载链接】LaTeX-Workshop Boost LaTeX typesetting efficiency with preview, compile, autocomplete, colorize, and more. 项目地址: https://gitcode.com/gh_mirrors/la/LaTeX-Worksh…...

一键切换模型:OpenClaw同时管理多个SecGPT-14B实例

一键切换模型&#xff1a;OpenClaw同时管理多个SecGPT-14B实例 1. 为什么需要管理多个模型实例 去年我在搭建本地AI安全分析系统时&#xff0c;遇到了一个典型困境&#xff1a;当SecGPT-14B模型需要版本升级时&#xff0c;整个服务必须停机。更糟的是&#xff0c;有次模型推理…...

ReactNative项目OpenHarmony三方库集成实战:react-native-render-html

欢迎加入开源鸿蒙跨平台社区&#xff1a;https://openharmonycrossplatform.csdn.net 项目基于 RN 0.72.90 开发 &#x1f4cb; 前言 在移动应用开发中&#xff0c;HTML 内容渲染是一项常见需求&#xff0c;特别是在新闻资讯、富文本编辑、邮件展示等场景中。React Native 原…...

Mavlink协议解析:从Pixhawk飞控到QGC地面站的完整通信流程

Mavlink协议深度解析&#xff1a;构建Pixhawk与QGC的高效通信桥梁 当Pixhawk飞控的LED指示灯开始规律闪烁&#xff0c;QGC地面站的地图上突然出现了一个蓝色圆点——这看似简单的连接背后&#xff0c;隐藏着一套精密的通信语言体系。Mavlink协议就像无人机系统的神经网络&#…...

Python智能自动化:JianYingApi赋能视频处理新范式

Python智能自动化&#xff1a;JianYingApi赋能视频处理新范式 【免费下载链接】JianYingApi Third Party JianYing Api. 第三方剪映Api 项目地址: https://gitcode.com/gh_mirrors/ji/JianYingApi 在数字内容创作领域&#xff0c;视频处理的智能化与自动化已成为提升效率…...

StreamIO:Arduino嵌入式统一I/O流与缓冲区抽象库

1. StreamIO 库概述StreamIO 是一个面向嵌入式 Arduino 生态的轻量级 I/O 抽象封装库&#xff0c;其核心设计目标是统一处理流式数据&#xff08;Stream&#xff09;与静态内存缓冲区&#xff08;array buffer&#xff09;的读写操作。在传统 Arduino 开发中&#xff0c;开发者…...

从85分到95+:复盘我在科大奥锐虚拟仿真实验平台踩过的那些‘坑’

从85分到95&#xff1a;科大奥锐虚拟仿真实验平台的实战避坑指南 第一次接触科大奥锐虚拟仿真实验平台时&#xff0c;我和大多数同学一样&#xff0c;以为这不过是传统实验的电子版。直到连续三次实验分数卡在85分上下&#xff0c;才意识到这个平台对操作细节的严苛程度远超预期…...

拯救受损二维码:用QRazyBox实现高效恢复的4个实战策略

拯救受损二维码&#xff1a;用QRazyBox实现高效恢复的4个实战策略 【免费下载链接】qrazybox QR Code Analysis and Recovery Toolkit 项目地址: https://gitcode.com/gh_mirrors/qr/qrazybox QRazyBox是一款专业的二维码分析与恢复工具包&#xff08;QR Code Analysis …...

ROS2(2)配置:从WSL网络到Docker容器GUI显示的完整链路

1. WSL2网络架构解析与ROS2容器网络配置 在WSL2Docker环境中运行ROS2时&#xff0c;网络问题是最常见的拦路虎。我刚开始用这个组合时&#xff0c;经常遇到镜像拉取超时、容器内无法访问外网的情况&#xff0c;后来才发现问题出在对WSL2网络机制的理解不足上。 WSL2采用虚拟化技…...