【设计模式】【结构型模式(Structural Patterns)】之装饰模式(Decorator Pattern)
1. 设计模式原理说明
装饰模式(Decorator Pattern) 是一种结构型设计模式,它允许在不改变对象接口的前提下,动态地给对象增加额外的责任或功能。这种模式创建了一个装饰类,用于包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
主要角色
- Component(组件):定义了一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent(具体组件):定义了一个具体的对象,也可以给这个对象添加一些责任。
- Decorator(装饰器):持有一个
Component
对象的实例,并定义了一个与Component
接口一致的接口。 - ConcreteDecorator(具体装饰器):向组件添加新的责任,通常通过在其前后添加行为来实现。
2. UML 类图及解释
UML 类图
+-----------------+ +-----------------+
| Component | | ConcreteComponent|
|-----------------| |-----------------|
| + operation(): void| | + operation(): void|
+-----------------+ +-----------------+^ ^| || |v v
+-----------------+
| Decorator |
|-----------------|
| - component: Component |
| + setComponent(component: Component)|
| + operation(): void |
+-----------------+^||v
+-----------------+ +-----------------+
| ConcreteDecoratorA| | ConcreteDecoratorB|
|-----------------| |-----------------|
| + operation(): void| | + operation(): void|
| + addedBehavior(): void| | + addedBehavior(): void|
+-----------------+ +-----------------+
类图解释
- Component:定义了一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent:定义了一个具体的对象,也可以给这个对象添加一些责任。
- Decorator:持有一个
Component
对象的实例,并定义了一个与Component
接口一致的接口。装饰器可以在其前后添加行为。 - ConcreteDecoratorA 和 ConcreteDecoratorB:具体装饰器,向组件添加新的责任,通常通过在其前后添加行为来实现。
3. 代码案例及逻辑详解
Java 代码案例
// 组件接口
interface Component {void operation();
}// 具体组件
class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent operation");}
}// 装饰器
abstract class Decorator implements Component {protected Component component;public void setComponent(Component component) {this.component = component;}@Overridepublic void operation() {if (component != null) {component.operation();}}
}// 具体装饰器 A
class ConcreteDecoratorA extends Decorator {@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("ConcreteDecoratorA added behavior");}
}// 具体装饰器 B
class ConcreteDecoratorB extends Decorator {@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("ConcreteDecoratorB added behavior");}
}// 客户端
public class Client {public static void main(String[] args) {Component component = new ConcreteComponent();ConcreteDecoratorA decoratorA = new ConcreteDecoratorA();ConcreteDecoratorB decoratorB = new ConcreteDecoratorB();decoratorA.setComponent(component);decoratorB.setComponent(decoratorA);decoratorB.operation();// 输出:// ConcreteComponent operation// ConcreteDecoratorA added behavior// ConcreteDecoratorB added behavior}
}
C++ 代码案例
#include <iostream>// 组件接口
class Component {
public:virtual void operation() = 0;virtual ~Component() {}
};// 具体组件
class ConcreteComponent : public Component {
public:void operation() override {std::cout << "ConcreteComponent operation" << std::endl;}
};// 装饰器
class Decorator : public Component {
protected:Component* component;public:void setComponent(Component* component) {this->component = component;}void operation() override {if (component != nullptr) {component->operation();}}
};// 具体装饰器 A
class ConcreteDecoratorA : public Decorator {
public:void operation() override {Decorator::operation();addedBehavior();}void addedBehavior() {std::cout << "ConcreteDecoratorA added behavior" << std::endl;}
};// 具体装饰器 B
class ConcreteDecoratorB : public Decorator {
public:void operation() override {Decorator::operation();addedBehavior();}void addedBehavior() {std::cout << "ConcreteDecoratorB added behavior" << std::endl;}
};// 客户端
int main() {Component* component = new ConcreteComponent();Decorator* decoratorA = new ConcreteDecoratorA();Decorator* decoratorB = new ConcreteDecoratorB();decoratorA->setComponent(component);decoratorB->setComponent(decoratorA);decoratorB->operation();// 输出:// ConcreteComponent operation// ConcreteDecoratorA added behavior// ConcreteDecoratorB added behaviordelete component;delete decoratorA;delete decoratorB;return 0;
}
Python 代码案例
from abc import ABC, abstractmethod# 组件接口
class Component(ABC):@abstractmethoddef operation(self):pass# 具体组件
class ConcreteComponent(Component):def operation(self):print("ConcreteComponent operation")# 装饰器
class Decorator(Component):def __init__(self, component: Component):self._component = componentdef operation(self):if self._component:self._component.operation()# 具体装饰器 A
class ConcreteDecoratorA(Decorator):def operation(self):super().operation()self.added_behavior()def added_behavior(self):print("ConcreteDecoratorA added behavior")# 具体装饰器 B
class ConcreteDecoratorB(Decorator):def operation(self):super().operation()self.added_behavior()def added_behavior(self):print("ConcreteDecoratorB added behavior")# 客户端
if __name__ == "__main__":component = ConcreteComponent()decorator_a = ConcreteDecoratorA(component)decorator_b = ConcreteDecoratorB(decorator_a)decorator_b.operation()# 输出:# ConcreteComponent operation# ConcreteDecoratorA added behavior# ConcreteDecoratorB added behavior
Go 代码案例
package mainimport "fmt"// 组件接口
type Component interface {Operation()
}// 具体组件
type ConcreteComponent struct{}func (c *ConcreteComponent) Operation() {fmt.Println("ConcreteComponent operation")
}// 装饰器
type Decorator struct {component Component
}func (d *Decorator) SetComponent(component Component) {d.component = component
}func (d *Decorator) Operation() {if d.component != nil {d.component.Operation()}
}// 具体装饰器 A
type ConcreteDecoratorA struct {Decorator
}func (c *ConcreteDecoratorA) Operation() {c.Decorator.Operation()c.AddedBehavior()
}func (c *ConcreteDecoratorA) AddedBehavior() {fmt.Println("ConcreteDecoratorA added behavior")
}// 具体装饰器 B
type ConcreteDecoratorB struct {Decorator
}func (c *ConcreteDecoratorB) Operation() {c.Decorator.Operation()c.AddedBehavior()
}func (c *ConcreteDecoratorB) AddedBehavior() {fmt.Println("ConcreteDecoratorB added behavior")
}// 客户端
func main() {component := &ConcreteComponent{}decoratorA := &ConcreteDecoratorA{Decorator: Decorator{component: component}}decoratorB := &ConcreteDecoratorB{Decorator: Decorator{component: decoratorA}}decoratorB.Operation()// 输出:// ConcreteComponent operation// ConcreteDecoratorA added behavior// ConcreteDecoratorB added behavior
}
4. 总结
装饰模式 是一种结构型设计模式,它允许在不改变对象接口的前提下,动态地给对象增加额外的责任或功能。这种模式通过创建装饰类来包装原有类,并在保持类方法签名完整性的前提下,提供了额外的功能。
主要优点
- 灵活性:可以在运行时动态地添加或删除对象的责任,而不需要修改现有的代码。
- 可扩展性:可以很容易地通过组合不同的装饰器来实现复杂的功能。
- 符合开闭原则:可以在不修改现有代码的情况下,通过添加新的装饰器来扩展功能。
主要缺点
- 增加了系统的复杂性:装饰模式会引入许多小类,这可能会使系统的设计变得更复杂。
- 调试困难:由于装饰器可以层层嵌套,调试时可能难以跟踪到最终的行为。
适用场景
- 当需要在运行时动态地给对象添加功能时。
- 当需要扩展类的功能,但又不想使用继承的方式时。
- 当系统需要提供多种可选功能,且这些功能可以自由组合时。
相关文章:
【设计模式】【结构型模式(Structural Patterns)】之装饰模式(Decorator Pattern)
1. 设计模式原理说明 装饰模式(Decorator Pattern) 是一种结构型设计模式,它允许在不改变对象接口的前提下,动态地给对象增加额外的责任或功能。这种模式创建了一个装饰类,用于包装原有的类,并在保持类方法…...

【AI】JetsonNano启动时报错:soctherm OC ALARM
1、问题描述 将JetsonNano烧写SD卡镜像为Ubuntu20.04后,启动时报错:soctherm OC ALARM,启动失败;然后系统一直重启 2、原因分析 “soctherm OC ALARM”是检测到系统温度超过安全阈值时发出的过热警告。 “soctherm”代表系统…...

QT:生成二维码 QRCode
目录 1.二维码历史2.QT源码3.界面展示4.工程源码链接 1.二维码历史 二维码(2-Dimensional Bar Code),是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的。它是指在一维条码…...

【LeetCode刷题之路】120:三角形最小路径和的两种解法(动态规划优化)
LeetCode刷题记录 🌐 我的博客主页:iiiiiankor🎯 如果你觉得我的内容对你有帮助,不妨点个赞👍、留个评论✍,或者收藏⭐,让我们一起进步!📝 专栏系列:LeetCode…...

神经网络中常见的激活函数Sigmoid、Tanh和ReLU
激活函数在神经网络中起着至关重要的作用,它们决定了神经元的输出是否应该被激活以及如何非线性地转换输入信号。不同的激活函数适用于不同的场景,选择合适的激活函数可以显著影响模型的性能和训练效率。以下是三种常见的激活函数:Sigmoid、T…...

适用于学校、医院等低压用电场所的智能安全配电装置
引言 电力,作为一种清洁且高效的能源,极大地促进了现代生活的便捷与舒适。然而,与此同时,因使用不当或维护缺失等问题,漏电、触电事件以及电气火灾频发,对人们的生命安全和财产安全构成了严重威胁…...

基于python爬虫的智慧人才数据分析系统
废话不多说,先看效果图 更多效果图可私信我获取 源码分享 import os import sysdef main():"""Run administrative tasks."""os.environ.setdefault(DJANGO_SETTINGS_MODULE, 智慧人才数据分析系统.settings)try:from django.core.m…...

LeetCode-315. Count of Smaller Numbers After Self
目录 题目描述 解题思路 【C】 【Java】 复杂度分析 LeetCode-315. Count of Smaller Numbers After Selfhttps://leetcode.com/problems/count-of-smaller-numbers-after-self/description/ 题目描述 Given an integer array nums, return an integer array counts whe…...

根据导数的定义计算导函数
根据导数的定义计算导函数 1. Finding derivatives using the definition (使用定义求导)1.1. **We want to differentiate f ( x ) 1 / x f(x) 1/x f(x)1/x with respect to x x x**</font>1.2. **We want to differentiate f ( x ) x f(x) \sqrt{x} f(x)x wi…...
WPF关于打开新窗口获取数据的回调方法的两种方式
一种基于消息发送模式 一种基于回调机制 基于消息发送模式 父页面定义接收的_selectedPnNumberStandarMsg保证是唯一 Messenger.Default.Register<PlateReplaceApplyModel>(this, _selectedPnNumberStandarMsgToken, platePnNumberModel > { …...

复杂网络(四)
一、规则网络 孤立节点网络全局耦合网络(又称完全网络)星型网络一维环二维晶格 编程实践: import networkx as nx import matplotlib.pyplot as pltn 10 #创建孤立节点图 G1 nx.Graph() G1.add_nodes_from(list(range(n))) plt.figure(f…...

用MATLAB符号工具建立机器人的动力学模型
目录 介绍代码功能演示拉格朗日方法回顾求解符号表达式数值求解 介绍 开发机器人过程中经常需要用牛顿-拉格朗日法建立机器人的动力学模型,表示为二阶微分方程组。本文以一个二杆系统为例,介绍如何用MATLAB符号工具得到微分方程表达式,只需要…...

SQL优化与性能——数据库设计优化
数据库设计优化是提高数据库性能、确保数据一致性和支持业务增长的关键环节。无论是大型企业应用还是小型项目,合理的数据库设计都能够显著提升系统性能、减少冗余数据、优化查询响应时间,并降低维护成本。本章将深入探讨数据库设计中的几个关键技术要点…...

FPGA存在的意义:为什么adc连续采样需要fpga来做,而不会直接用iic来实现
FPGA存在的意义:为什么adc连续采样需要fpga来做,而不会直接用iic来实现 原因ADS111x连续采样实现连续采样功能说明iic读取adc的数据速率 VS adc连续采样的速率adc连续采样的速率iic读取adc的数据速率结论分析 FPGA读取adc数据问题一:读取adc数…...

我们来学mysql -- 事务之概念(原理篇)
事务的概念 题记一个例子一致性隔离性原子性持久性 题记 在漫长的编程岁月中,存在一如既往地贯穿着工作,面试的概念这类知识点,事不关己当然高高挂起,精准踩坑时那心情也的却是日了🐶请原谅我的粗俗,遇到B…...

基于特征子空间的高维异常检测:一种高效且可解释的方法
本文将重点探讨一种替代传统单一检测器的方法:不是采用单一检测器分析数据集的所有特征,而是构建多个专注于特征子集(即子空间)的检测器系统。 在表格数据的异常检测实践中,我们的目标是识别数据中最为异常的记录,这种异常性可以…...

看不见的彼方:交换空间——小菜一碟
有个蓝色的链接,先去看看两年前的题目的write up (https://github.com/USTC-Hackergame/hackergame2022-writeups/blob/master/official/%E7%9C%8B%E4%B8%8D%E8%A7%81%E7%9A%84%E5%BD%BC%E6%96%B9/README.md) 从别人的write up中了解到&…...
YOLO模型训练后的best.pt和last.pt区别
在选择YOLO模型训练后的权重文件best.pt和last.pt时,主要取决于具体的应用场景:12 best.pt:这个文件保存的是在训练过程中表现最好的模型权重。通常用于推理和部署阶段,因为它包含了在验证集上表现最好的模型权重&#x…...

Pareidoscope - 语言结构关联工具
文章目录 关于 Pareidoscope安装使用方法输入格式语料库查询 将语料库转换为 SQLite3 数据库两种语言结构之间的关联简单词素分析关联共现和伴随词素分析相关的更大结构可视化关联结构 关于 Pareidoscope Pareidoscope 是一组 用于确定任意语言结构之间 关联的工具,…...
GPT(Generative Pre-trained Transformer) 和 Transformer的比较
GPT(Generative Pre-trained Transformer) 和 Transformer 的比较 flyfish 1. Transformer 是一种模型架构 Transformer 是一种通用的神经网络架构,由 Vaswani 等人在论文 “Attention Is All You Need”(2017)中提…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...

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

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...