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

(八)趣学设计模式 之 装饰器模式!

在这里插入图片描述

目录

    • 一、 啥是装饰器模式?
    • 二、 为什么要用装饰器模式?
    • 三、 装饰器模式的实现方式
    • 四、 装饰器模式的优缺点
    • 五、 装饰器模式的应用场景
    • 六、 装饰器模式 vs 代理模式
    • 七、 总结

🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解适配器模式请看: (七)趣学设计模式 之 适配器模式!

这篇文章带你详细认识一下设计模式中的装饰器模式

一、 啥是装饰器模式?

想象一下,你点了一杯咖啡 ☕️,觉得味道有点单调,想加点料,比如加一份牛奶 🥛,或者加一份糖 🍬,甚至加一份巧克力酱 🍫。 每次加料,咖啡的味道都会变得不一样 😋。

装饰器模式,就是用来动态地给一个对象添加一些额外的职责! 它可以让你在不修改原有对象的基础上,扩展对象的功能 ➕。

简单来说,就是给对象穿上不同的“衣服”,让它拥有不同的功能! 🧥👔

  • 你想给一个对象添加一些额外的功能,但是不想修改它的代码: 就像你想给咖啡加料,但是不想修改咖啡的制作方法 ☕️!
  • 你想动态地给对象添加功能,而不是静态地继承: 就像你想根据自己的喜好,随时给咖啡加不同的料 🥛🍬🍫!
  • 你想避免创建大量的子类: 就像你不想为每种加料的咖啡都创建一个新的类 ☕️+🥛, ☕️+🍬, ☕️+🍫!

二、 为什么要用装饰器模式?

用装饰器模式,好处多多 👍:

  • 扩展性好: 可以动态地添加新的装饰器,扩展对象的功能 ➕!
  • 灵活性高: 可以灵活地组合不同的装饰器,实现不同的功能组合 🤸!
  • 符合开闭原则: 可以在不修改原有代码的情况下,增加新的装饰器,扩展功能 🆕!
  • 避免了继承带来的类爆炸问题: 不需要创建大量的子类,减少了类的数量 💥!

三、 装饰器模式的实现方式

装饰器模式主要包含以下几个角色:

  • Component(组件): 定义一个对象接口,可以给这些对象动态地添加职责。 ☕️ (比如:咖啡)
  • ConcreteComponent(具体组件): 定义一个具体的对象,实现了组件接口。 ☕️ (比如:原味咖啡)
  • Decorator(装饰器): 包含一个指向组件对象的引用,并定义一个与组件接口一致的接口。 🧥 (比如:调味品)
  • ConcreteDecorator(具体装饰器): 具体的装饰器类,负责给组件对象添加额外的职责。 🥛🍬🍫 (比如:牛奶、糖、巧克力酱)

代码示例:

// 组件接口:咖啡
public interface Coffee {String getDescription(); // 获取描述double getCost(); // 获取价格
}// 具体组件:原味咖啡
public class SimpleCoffee implements Coffee {@Overridepublic String getDescription() {return "原味咖啡";}@Overridepublic double getCost() {return 10.0;}
}// 装饰器:调味品
public abstract class CoffeeDecorator implements Coffee {protected Coffee coffee; // 组合咖啡对象public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}@Overridepublic String getDescription() {return coffee.getDescription();}@Overridepublic double getCost() {return coffee.getCost();}
}// 具体装饰器:牛奶
public class Milk extends CoffeeDecorator {public Milk(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return super.getDescription() + ", 加牛奶";}@Overridepublic double getCost() {return super.getCost() + 2.0;}
}// 具体装饰器:糖
public class Sugar extends CoffeeDecorator {public Sugar(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return super.getDescription() + ", 加糖";}@Overridepublic double getCost() {return super.getCost() + 1.0;}
}// 客户端
public class Client {public static void main(String[] args) {Coffee coffee = new SimpleCoffee(); // 创建原味咖啡System.out.println(coffee.getDescription() + ", 价格:" + coffee.getCost());coffee = new Milk(coffee); // 加牛奶System.out.println(coffee.getDescription() + ", 价格:" + coffee.getCost());coffee = new Sugar(coffee); // 加糖System.out.println(coffee.getDescription() + ", 价格:" + coffee.getCost());}
}

分析:

  • Coffee 是组件接口,定义了咖啡的描述和价格。
  • SimpleCoffee 是具体组件,实现了原味咖啡。
  • CoffeeDecorator 是装饰器,组合了咖啡对象,并实现了咖啡接口。
  • MilkSugar 是具体装饰器,分别给咖啡添加了牛奶和糖。

输出结果:

原味咖啡, 价格:10.0
原味咖啡, 加牛奶, 价格:12.0
原味咖啡, 加牛奶, 加糖, 价格:13.0

四、 装饰器模式的优缺点

优点:

  • 扩展性好 ➕!
  • 灵活性高 🤸!
  • 符合开闭原则 🆕!
  • 避免了继承带来的类爆炸问题 💥!

缺点:

  • 增加了系统的复杂度 😫!
  • 可能会产生很多小对象 👶!
  • 调试困难,特别是当有很多装饰器的时候 🐛!

五、 装饰器模式的应用场景

  • 动态地给对象添加职责: 就像给咖啡加料,或者给汽车加装配件 🚗!
  • 需要灵活地组合不同的功能: 就像给文本编辑器添加不同的功能,比如加粗、斜体、下划线 📝!
  • 避免创建大量的子类: 就像避免为每种加料的咖啡都创建一个新的类 ☕️+🥛, ☕️+🍬, ☕️+🍫!
  • IO流: Java IO流中大量使用了装饰器模式,例如 BufferedInputStreamBufferedOutputStream 都是装饰器,用于提高IO效率。

六、 装饰器模式 vs 代理模式

代理模式请看:(六)趣学设计模式 之 代理模式!

特性装饰器模式代理模式
目的动态地给对象添加额外的职责 ➕控制对对象的访问 👮
关注点扩展功能控制访问
关系装饰器和组件之间是“is-a”关系(接口)代理和真实对象之间是“is-a”关系(接口)
组合装饰器组合的是组件对象,可以多层组合 ☕️+🥛+🍬代理组合的是真实对象,通常只有一层 🧑‍💼+🏠
透明性客户端通常知道它正在使用装饰器 👁️客户端通常不知道它正在使用代理 🙈
例子咖啡加料 ☕️+🥛+🍬房产中介 🧑‍💼+🏠
常见应用IO流,GUI组件远程代理,虚拟代理,保护代理,缓存代理
核心区别扩展对象的功能,不改变原有接口控制对对象的访问,可以改变原有接口的行为

七、 总结

  • 装饰器模式就像给对象穿衣服,让它拥有不同的功能! 🧥
  • 主要包含组件、具体组件、装饰器和具体装饰器四个角色! 🎭
  • 优点是扩展性好、灵活性高、符合开闭原则、避免类爆炸! 👍
  • 缺点是增加复杂度、可能产生很多小对象、调试困难! 👎
  • 适用于需要动态地给对象添加职责,并且需要灵活地组合不同的功能的场景! 🎯

希望这篇文章能让你彻底理解装饰器模式! 💯 祝你学习愉快! 😄
看完请看:(九)趣学设计模式 之 桥接模式!

相关文章:

(八)趣学设计模式 之 装饰器模式!

目录 一、 啥是装饰器模式?二、 为什么要用装饰器模式?三、 装饰器模式的实现方式四、 装饰器模式的优缺点五、 装饰器模式的应用场景六、 装饰器模式 vs 代理模式七、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢…...

设计后端返回给前端的返回体

目录 1、为什么要设计返回体? 2、返回体包含哪些内容(如何设计)? 举例 3、总结 1、为什么要设计返回体? 在设计后端返回给前端的返回体时,通常需要遵循一定的规范,以确保前后端交互的清晰性…...

Element Plus中el-select选择器的下拉选项列表的样式设置

el-select选择器,默认样式效果: 通过 * { margin: 0; padding: 0; } 去掉内外边距后的样式效果(样式变丑了): 通过 popper-class 自定义类名修改下拉选项列表样式 el-select 标签设置 popper-class"custom-se…...

C高级(shell)

作业 1、使用case...in实现等级判断 2、计算各个位数和 3、计算家目录下目录个数和普通文件数 4、打印图形 5、冒泡排序...

子宫腺肌症是如果引起的?

子宫腺肌症是一种常见的妇科疾病,它是指子宫内膜的腺体和间质侵入子宫肌层形成的一种病症。那么,子宫腺肌症是如何引起的呢? 一、病因分析 子宫腺肌症的确切病因目前尚不十分清楚,但经过医学研究和临床观察,认为其发…...

网络安全学习中,web渗透的测试流程是怎样的?

渗透测试是什么?网络安全学习中,web渗透的测试流程是怎样的? 渗透测试就是利用我们所掌握的渗透知识,对网站进行一步一步的渗透,发现其中存在的漏洞和隐藏的风险,然后撰写一篇测试报告,提供给我…...

【软考】【2025年系统分析师拿证之路】【啃书】第十四章 软件实现与测试(十五)

目录 程序设计方法代码重用软件测试软件测试的对象和目的软件测试方法按照被测程序是否可见分类按照是否需要执行被测试程序分类自动测试 测试类型按测试对象划分按测试阶段划分按被测试软件划分其他分类 程序设计方法 结构化程序设计:自顶向下,逐步求精…...

自然语言处理NLP深探

1. NLP 的定义、特点、具体工作、历史和流派 定义:自然语言处理(Natural Language Processing,NLP)是计算机科学与人工智能领域的一个重要分支,旨在让计算机理解、处理和生成人类自然语言,实现人与计算机之间用自然语言进行有效通信。特点 交叉性:涉及计算机科学、语言学…...

加载互联网免费地图资源并通过CesiumEarth快速浏览

免费地图资源 地理信息系统(GIS)的搭建主要可分为两部分:1、三维地球引擎;2、基础数据图层。 CesiumEarth提供了可直接使用的三维地球引擎,因此只需准备基础数据图层,即可搭建属于自己的地理信息系统。 …...

Android 键盘输入按确认或换行 直接触发提交

在 Android 开发中,若要实现键盘输入时按下确认键(如 “完成”“发送” 等)或者换行键直接触发提交操作,可以通过以下几种方式实现,下面为你详细介绍。 方式一:使用 EditText 的 setOnEditorActionListene…...

halcon三维点云数据处理(二十七)remove_bin_for_3d_object_localization

目录 一、remove_bin_for_3d_object_localization代码第一部分二、remove_bin_for_3d_object_localization代码第二部分三、效果图一、remove_bin_for_3d_object_localization代码第一部分 1、读图构建3D模型。 2、一次二值化选取区域。 3、一次和背景差值选取区域。 4、在二维…...

XFeat:轻量级的深度学习图像特征匹配

一、引言:图像特征匹配的挑战与XFeat的突破 在计算机视觉领域,图像特征匹配是视觉定位(Visual Localization)、三维重建(3D Reconstruction)、增强现实(AR)等任务的核心基础。传统方…...

[MD] AG stable

当然,以下是A-stable和G-stable的详细定义: A-stable (A-稳定) A-stable是数值方法稳定性的一种分类,主要用于分析求解常微分方程初值问题的数值方法。一个数值方法被称为A-stable,如果它满足以下条件: 对于所有的步…...

微信小程序自定义导航栏实现指南

文章目录 微信小程序自定义导航栏实现指南一、自定义导航栏的需求分析二、代码实现1. WXML 结构2. WXSS 样式样式解析:3. JavaScript 逻辑三、完整代码示例四、注意事项与优化建议五、总结微信小程序自定义导航栏实现指南 在微信小程序开发中,默认的导航栏样式可能无法满足所…...

wav格式的音频压缩,WAV 转 MP3 VBR 体积缩减比为 13.5%、多个 MP3 格式音频合并为一个、文件夹存在则删除重建,不存在则直接建立

🥇 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 🎉 声明: 作为全网 AI 领域 干货最多的博主之一,❤️ 不负光阴不负卿 ❤️ 文章目录 问题一:wav格式的音频压缩为哪些格式,网络传输给用户播放…...

面试问题——如何解决移动端1px 边框问题?

面试问题——如何解决移动端1px 边框问题? 最近,不少小伙伴向我反映,他们在面试中频繁被问到关于1px边框的问题。这个看似老生常谈的话题,没想到在面试中的出现率依然这么高,着实让我有些意外。对于那些对这个问题感到…...

鸿蒙开发第4篇__关于在鸿蒙应用中使用Java语言进行设计

本博文很重要 HarmonyOS从 API8 开始不再支持使用Java作为开发语言,未来的新功能将在ArkTS中实现. API 8对应的是HarmonyOS 3.0.0版本。请看下图: 因此, 读者如果看到类似《鸿蒙应用程序开发》(2021年版本 清华大学出版计)书 还使用Java语言…...

什么是Ollama?什么是GGUF?二者之间有什么关系?

一、Ollama:本地化大模型运行框架 Ollama 是一款开源工具,专注于在本地环境中快速部署和运行大型语言模型(LLM)。它通过极简的命令行操作简化了模型管理流程,支持离线运行、多模型并行、私有化部署等场景。 核心特性 本地化运行:无需依赖云端API,用户可在个人电脑或服务…...

kubernetes 初学命令

基础命令 kubectl 运维命令常用: #查看pod创建过程以及相关日志 kubectl describe pod pod-command -n dev #查看某个pod,以yaml格式展示结果 kubectl get pod nginx -o yaml #查看pod 详情 以及对应的集群IP地址 kubectl get pods -o wide 1. kubetc…...

useLayoutEffect和useEffect有什么区别?

在 React 中,useEffect 和 useLayoutEffect 是两个用于处理副作用的 Hook。虽然它们在用法上相似,但在执行时间和适用场景上有显著的区别。以下是对这两个 Hook 的详细比较和解释。 1. 基本概念 useEffect 定义:useEffect 是一个 Hook&…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...