设计模式-结构型-装饰器模式
装饰器模式(Decorator Pattern)是结构型设计模式中的一种,它允许你通过将对象封装在一个新的对象中,来动态地添加新的功能,而无需改变原对象的结构。装饰器模式的核心思想是“将功能附加到对象上”,它是一种对象行为增强的模式。该模式通过组合而非继承来扩展对象的功能,这使得它比继承更灵活。
装饰器模式的定义
装饰器模式允许在不修改对象本身的情况下,动态地给一个对象添加额外的功能。其基本结构如下:
- Component:定义一个对象接口,可以为其他对象提供基础功能。
- ConcreteComponent:实现
Component接口的具体类,是需要被装饰的原始对象。 - Decorator:持有一个
Component对象,并通过继承或实现该接口来增加附加功能。 - ConcreteDecorator:具体的装饰类,它实现了装饰器接口,包装了
ConcreteComponent,并增加了新的功能。
装饰器模式的实现
在 Python 中,装饰器模式通常使用类继承和组合的方式实现。为了更清晰地理解装饰器模式,我们可以通过一个示例进行讲解。
代码示例
假设我们有一个 Car 类,表示普通的汽车,车主希望能够动态地为这辆车添加新功能,例如导航系统和音响系统。我们可以通过装饰器模式为 Car 类动态地增加这些功能。
# 1. 基础组件接口
class Car:def features(self):raise NotImplementedError("Subclass must implement abstract method")# 2. 具体组件:原始的汽车类
class BasicCar(Car):def features(self):return "Basic Car Features"# 3. 装饰器类:持有一个 Car 对象
class CarDecorator(Car):def __init__(self, car):self._car = cardef features(self):return self._car.features()# 4. 具体装饰器:为汽车添加导航功能
class NavigationSystem(CarDecorator):def features(self):return f"{self._car.features()}, Navigation System"# 5. 具体装饰器:为汽车添加音响系统
class SoundSystem(CarDecorator):def features(self):return f"{self._car.features()}, Sound System"# 使用装饰器
basic_car = BasicCar()
print("Basic Car:", basic_car.features())# 添加导航功能
car_with_navigation = NavigationSystem(basic_car)
print("Car with Navigation:", car_with_navigation.features())# 添加音响功能
car_with_navigation_and_sound = SoundSystem(car_with_navigation)
print("Car with Navigation and Sound System:", car_with_navigation_and_sound.features())
输出结果
Basic Car: Basic Car Features
Car with Navigation: Basic Car Features, Navigation System
Car with Navigation and Sound System: Basic Car Features, Navigation System, Sound System
解释
- BasicCar:原始汽车类,实现了
Car接口,提供了基本的汽车功能。 - CarDecorator:装饰器基类,它持有一个
Car对象,并通过features()方法传递对原始Car功能的调用。 - NavigationSystem 和 SoundSystem:具体的装饰类,它们分别为汽车增加了导航和音响功能。
通过使用装饰器模式,我们可以动态地为 Car 添加新功能,而无需修改 BasicCar 类本身。
装饰器模式的优点
-
增强功能的灵活性:
- 通过装饰器模式,可以在运行时根据需求动态地为对象增加功能,而无需修改类的代码。它提供了一种非常灵活的方式来增强对象的行为。
-
符合开闭原则:
- 装饰器模式符合设计原则中的开闭原则:对扩展开放,对修改关闭。你可以通过装饰器为现有类添加新功能,而无需修改现有代码。
-
避免了继承层次的膨胀:
- 通过装饰器模式,我们不需要使用继承来增加新功能,从而避免了继承层次的复杂性。每个装饰类只负责一个功能,可以随意组合,避免了多重继承的繁琐。
-
组合与复用:
- 装饰器模式支持多重组合,可以灵活地为对象组合多个功能,每个功能都可以由不同的装饰器来处理,使得代码复用性更高。
装饰器模式的缺点
-
增加系统复杂度:
- 尽管装饰器模式提供了灵活的扩展性,但在实际使用时,过多的装饰器类可能导致系统变得复杂,难以管理和理解。
-
类数量激增:
- 每一个新的装饰类都可能成为系统中的一个新类。如果有很多功能需要动态添加,可能会导致类的数量剧增,增加系统的维护成本。
-
调试困难:
- 在使用装饰器模式时,调试可能会变得更加困难,因为装饰器通常是动态地改变对象的行为,跟踪这些变化可能需要更多的调试工具支持。
装饰器模式的实际应用
装饰器模式在许多实际应用中都有广泛的使用,特别是在需要动态增强对象功能的场景中。以下是一些典型应用场景:
-
输入输出流:
- 在 Java 中,装饰器模式常用于输入输出流的处理(例如:
BufferedReader和FileReader)。每个类都为流对象添加不同的功能,而不需要修改原始对象的代码。
- 在 Java 中,装饰器模式常用于输入输出流的处理(例如:
-
GUI控件:
- 在图形用户界面(GUI)中,装饰器模式常用于为界面组件(如按钮、文本框)动态添加功能。例如,动态为按钮添加点击事件、为文本框添加验证功能等。
-
Web开发中的请求处理:
- 在 Web 开发中,装饰器模式通常用于处理 HTTP 请求和响应,例如:在请求进入处理函数前动态地为请求添加身份验证、日志记录、权限控制等功能。
-
缓存和日志:
- 通过装饰器模式,可以在现有功能的基础上为数据处理添加缓存或日志功能,而不需要修改核心业务逻辑。
总结
装饰器模式是一种强大的设计模式,提供了一种灵活的方式来扩展对象的功能。通过将对象封装在另一个对象中,装饰器可以在不修改原始对象的情况下,为对象添加新的行为。这种模式使得我们可以通过组合多个装饰器来动态增加功能,而避免了类继承的复杂性,符合“开闭原则”。然而,过度使用装饰器模式可能导致系统复杂度和类数量的激增,因此需要谨慎使用。
相关文章:
设计模式-结构型-装饰器模式
装饰器模式(Decorator Pattern)是结构型设计模式中的一种,它允许你通过将对象封装在一个新的对象中,来动态地添加新的功能,而无需改变原对象的结构。装饰器模式的核心思想是“将功能附加到对象上”,它是一种…...
git详细使用教程
文章目录 一、 git介绍与安装1、git介绍2、git的安装3、git使用前的说明 二、git的基础使用1、走进git之前2、git基础使用1、git init 项目初始化(init)成仓库(repository)2、git add 管理文件3、git commit 把文件提交到仓库&…...
java实现word转html(支持docx及doc文件)
private final static String tempPath "C:\\Users\\xxx\\Desktop\\Word2Html\\src\\test\\";//图片及相关文件保存的路径public static void main(String argv[]) {try {JFileChooser fileChooser new JFileChooser();fileChooser.setDialogTitle("Select a …...
搜维尔科技:Xsens人形机器人解决方案的优势
Xsens 致力于推动人形机器人技术的发展,塑造机器人与人类环境无缝融合的未来,通过创新精确和协作,协助生产和服务,改善人类生活和产业。 Xsens通过人形跟随捕捉详细的人体运动数据,使机器人能够学习类人的动作&#x…...
【王树森搜索引擎技术】概要01:搜索引擎的基本概念
1. 基本名词 query:查询词SUG:搜索建议文档:搜索结果标签/筛选项 文档单列曝光 文档双列曝光 2. 曝光与点击 曝光:用户在搜索结果页上看到文档,就算曝光文档点击:在曝光后,用户点击文档&…...
《Java核心技术II》可中断套接字
4.2.4 可中断套接字 SocketChannel可以中断套接字 SocketChannel channel.open(new InetSocketAddress(host,port)); 通道(channel)并没有与之相关联的流,实际上,所拥有的read和write方法都是通过Buffer对象实现的。 如果不想处理缓冲区,…...
基于 Python 的深度学习的车俩特征分析系统,附源码
博主介绍:✌stormjun、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…...
C#读写ini配置文件保存设置参数
本示例使用设备:https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1b5P5rkA&ftt&id22173428704 [DllImport("kernel32", CharSet CharSet.Unicode)] public static extern uint GetPrivateProfileString(string lpAppName, stri…...
SwanLab环境变量列表
文章目录 环境变量全局配置服务配置登录认证其他 环境变量 ⚙️完整环境变量1 -> Github、⚙️完整环境变量2 -> Github 全局配置 环境变量描述默认值SWANLAB_SAVE_DIRSwanLab 全局文件夹保存的路径用户主目录下的 .swanlab 文件夹SWANLAB_LOG_DIRSwanLab 解析日志文件…...
深度学习入门-CNN
一、CNN是什么 CNN,即卷积神经网络(convolutional neural network),是用于预测的标准神经网络架构。在人工智能的广阔领域中,CNN被用于图像识别、语音识别等各种场合,CNN通过模拟人类视觉皮层的神经元连接方…...
微服务网关,如何选择?
什么是API网关 API网关(API Gateway)是微服务架构中的一个关键组件,它充当了客户端与后端服务之间的中间层。其主要功能包括请求路由、协议转换、负载均衡、安全认证、限流熔断等。通过API网关,客户端无需直接与多个微服务交互&a…...
SpringBoot集成Mqtt服务实现消费发布和接收消费
该项目介绍了docker环境下如何安装mqtt和springboot集成mqtt服务 前述 MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,设计用于在资源受限的设备和低带宽、不可靠的网络连接中高效地传输数据。主要用于物联网设备传输,设备之间可以高效地交换数据…...
在Mac mini上实现本地话部署AI和知识库
在Mac mini上实现本地话部署AI和知识库 硬件要求:大模型AI,也叫LLM,需要硬件支持,常见的方式有2种:一种是采用英伟达之类支持CUDA库的GPU芯片或者专用AI芯片;第二种是采用苹果M系列芯片架构的支持统一内存架…...
一个方法被多个线程同时调用,确保同样参数的调用只能有一个线程执行,不同参数的调用则可以多个线程同时执行
我们知道通过lock一个固定静态object给代码段加同步锁,可以让多个线程的同时调用以同步执行,因此可以利用字典来给不同参数分配不同的静态对象,方法中不同的参数调用锁住各自不同的静态对象即可实现不同参数不加锁,相同参数才加锁…...
3. MySQL事务并发的问题与解决方法
一. 并发事务带来的问题 并发会造成事务间出现脏读,不可重复读,幻读现象。 1. 脏读 一个事务在处理过程中读取了另外一个事务未提交的数据。若另外一个事务回滚,则读取到的数据是无效的,又称为脏读。 2. 不可重复读 在一个事务…...
25/1/15 嵌入式笔记 初学STM32F108
GPIO初始化函数 GPIO_Ini:初始化GPIO引脚的模式,速度和引脚号 GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA的引脚0 GPIO输出控制函数 GPIO_SetBits:将指定的GPIO引脚设置为高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0); // 将GPIO…...
MySQL的不同SQL模式导致行为不同?
现象: 我在两个mysql库都有相同定义的表,其中一个字段是varchar(1200)。当我都对这个表进行insert操作,而且超过此字段的规定长度(此处是1200),这两库的行为是不一样的:库B是直接报错too long&…...
Flink 使用 Kafka 作为数据源时遇到了偏移量提交失败的问题
具体的错误日志 21:43:57.069 [Kafka Fetcher for Source: Custom Source -> Map -> Filter (1/1)#2] ERROR org.apache.kafka.clients.consumer.internals.ConsumerCoordinator - [Consumer clientIdconsumer-my-group-6, groupIdmy-group] Offset commit failed on pa…...
【日志篇】(7.6) ❀ 01. 在macOS下刷新FortiAnalyzer固件 ❀ FortiAnalyzer 日志分析
【简介】FortiAnalyzer 是 Fortinet Security Fabric 安全架构的基础,提供集中日志记录和分析,以及端到端可见性。因此,分析师可以更有效地管理安全状态,将安全流程自动化,并快速响应威胁。具有分析和自动化功能的集成…...
LSA更新、撤销
LSA的新旧判断: 1.seq,值越大越优先 2.chksum,值越大越优先 3.age,本地的LSA age和收到的LSA age作比较 如果差值<900s,认为age一致,保留本地的:我本地有一条LSA是100 你给的是400 差值小于…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
