设计模式--装饰者模式(Decorator Pattern)
一、什么是装饰者模式(Decorator Pattern)
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不修改现有对象的情况下,动态地将新功能附加到对象上。这种模式通过创建一个包装类,即装饰者,来包含原始对象,并在其上添加额外的行为或功能。这样,你可以在运行时选择不同的装饰者组合来实现不同的功能组合。
装饰者模式的关键思想是将功能细分为一系列小的组件,然后将这些组件通过装饰者按照需要进行组合。这种模式遵循开放-关闭原则,即对扩展开放,对修改关闭。
主要角色:
- 组件(Component): 定义了一个抽象接口,可以是具体组件和装饰者共同实现的接口,表示被装饰者的基本功能。
- 具体组件(Concrete Component): 实现了组件接口的具体对象,即被装饰的原始对象。
- 装饰者(Decorator): 保持一个指向组件对象的引用,并实现与组件接口相同的接口。它可以有多个具体装饰者的子类。
- 具体装饰者(Concrete Decorator): 扩展装饰者的功能,包装具体组件,并可能添加新的行为。
装饰者模式的优势包括:
- 可以动态地组合对象,实现不同的功能组合,避免了类爆炸问题(大量子类的产生)。
- 遵循开放-关闭原则,允许在不修改现有代码的情况下扩展功能。
然而,装饰者模式也可能引入大量的小类,增加了代码的复杂性。在使用装饰者模式时,需要谨慎选择需要装饰的组件,以及如何合理地组合装饰者,以确保代码的可读性和维护性。
二、装饰者模式的代码样例
当用C++实现装饰者模式时,我们可以通过创建基类(组件)和派生类(具体组件、装饰者、具体装饰者)来演示。以下是一个简单的示例:
#include <iostream>// 组件基类
class Coffee {
public:virtual double cost() = 0;virtual ~Coffee() {}
};// 具体组件
class Espresso : public Coffee {
public:double cost() override {return 1.99;}
};// 装饰者基类
class Decorator : public Coffee {
protected:Coffee* coffee;
public:Decorator(Coffee* coffee) : coffee(coffee) {}
};// 具体装饰者
class Milk : public Decorator {
public:Milk(Coffee* coffee) : Decorator(coffee) {}double cost() override {return coffee->cost() + 0.5;}
};class Sugar : public Decorator {
public:Sugar(Coffee* coffee) : Decorator(coffee) {}double cost() override {return coffee->cost() + 0.2;}
};int main() {Coffee* espresso = new Espresso();std::cout << "Cost of espresso: $" << espresso->cost() << std::endl;Coffee* milkEspresso = new Milk(espresso);std::cout << "Cost of milk espresso: $" << milkEspresso->cost() << std::endl;Coffee* milkSugarEspresso = new Sugar(milkEspresso);std::cout << "Cost of milk and sugar espresso: $" << milkSugarEspresso->cost() << std::endl;delete espresso;delete milkEspresso;delete milkSugarEspresso;return 0;
}
在这个示例中,我们定义了 Coffee 基类和一个具体组件 Espresso。然后,我们定义了 Decorator 基类,它包含了一个指向 Coffee 对象的引用,并有两个具体装饰者类 Milk 和 Sugar,它们分别在 Coffee 上添加了牛奶和糖的装饰。
在 main 函数中,我们创建了一个 Espresso 对象,然后通过装饰者模式依次创建了包含不同装饰的咖啡对象,并输出了其价格。
这个示例展示了如何使用C++实现装饰者模式,动态地为对象添加功能。
三、使用装饰者模式需要注意的问题
在使用装饰者模式时,需要注意以下几个问题:
- 类爆炸: 装饰者模式可能会引入大量的小类,每个装饰者都是一个单独的类。这可能会导致类的数量急剧增加,增加代码复杂性和维护成本。因此,在选择使用装饰者模式时,需要仔细权衡增加的类数量是否值得所提供的灵活性和扩展性。
- 装饰者顺序: 装饰者模式中,装饰者的顺序可能会影响最终的对象组合。你需要确保装饰者的顺序不会引起意外的行为,特别是在组合多个装饰者时。
- 代码可读性: 过度使用装饰者模式可能会使代码变得难以理解和维护。因为每个具体装饰者只负责添加一小部分功能,当功能需要嵌套多层装饰者时,代码可能会变得冗长且难以阅读。
- 接口一致性: 在创建装饰者时,需要确保它们与组件(基类)具有一致的接口。这样,装饰者才能无缝地替代组件,而不会引发类型不匹配的问题。
- 不适合所有情况: 装饰者模式适用于需要动态地添加功能的情况。如果功能不太可能改变,或者只有固定数量的组合方式,那么使用装饰者模式可能会过于复杂,不切实际。
- 继承和组合的选择: 在设计时,需要权衡是否使用继承或组合。装饰者模式使用了组合,但过多的组合也可能使系统变得复杂。在一些情况下,简单的继承可能更合适。
- 性能影响: 使用装饰者模式可能会在运行时引入一些额外的开销,因为每个装饰者都会对对象进行包装和处理。这可能会在需要高性能的场景下造成问题。
总之,在使用装饰者模式时,需要根据实际情况谨慎权衡,考虑其带来的灵活性和复杂性,确保模式的应用不会导致代码难以维护或性能下降。
相关文章:

设计模式--装饰者模式(Decorator Pattern)
一、什么是装饰者模式(Decorator Pattern) 装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不修改现有对象的情况下,动态地将新功能附加到对象上。这种模式通过创建一个包装类,…...

Spring三级缓存解决循环依赖
Spring三级缓存解决循环依赖 一 Spring bean对象的生命周期 二 三级缓存解决循环依赖 实现原理解析 spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决的,所说的缓存其实也就是三个Map 先实例化的bean会通过ObjectFactory半…...

Vscode自动移出不用的包
Vscode自动移出不用的包 在Vscode中删除不用的包、Vscode移出不用的包、Vscode移出不用的import包 设置 找到setting.json(在字体设置里面),添加如下配置 "editor.codeActionsOnSave": { "source.organizeImports": tru…...

leetcode做题笔记120. 三角形最小路径和
给定一个三角形 triangle ,找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一…...

weblogic/CVE-2018-2894文件上传漏洞复现
启动docker环境 查看帮助文档 环境启动后,访问http://your-ip:7001/console,即可看到后台登录页面。 执行docker-compose logs | grep password可查看管理员密码,管理员用户名为weblogic,密码为lFVAJ89F 登录后台页面,…...

windows10默认浏览器总是自动更改为Edge浏览器
在设置的默认应用设置中把默认浏览器改为chrome或其他之后他自动又会改回Edge。不得不说*软真的狗。 解决办法: 后来发现在Edge浏览器的设置中有这么一个选项,会很无耻的默认是Edge。把它关掉后重新设置就行了。...

系统架构设计师考试论文:论软件架构风格与应用
软件体系结构风格是描述某一特定应用领域中系统组织方式的惯用模式。体系结构风格定义一个系统家族,即一个体系结构定义一个词汇表和一纽约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。体系结构风格反…...

xss-labs靶场通关详解
文章目录 前言level1level2level3level4level5level6level7level8level9level10level11level12level13level14level15level16level17level18level19&level20 前言 赶着假期结尾的时候,赶紧给自己找点任务做。现在对xss还是一知半解,只是了解个大概&a…...

关于类和接口
类和接口的区别,去除语法层面,谈谈编程层面的意义。 设计原则SOLID: S:单一职责(SRP),Single Responsibility Principle O:开-闭原则(OCP),Open-Closed Principle L:里氏替换(LSP)&…...

网络安全社区与资源分享: 推荐网络安全社区、论坛、博客、培训资源等,帮助从业者拓展人脉和知识。
第一章:引言 在当今数字化的世界中,网络安全问题变得愈发突出。随着各种新型威胁的涌现,网络安全从业者面临着持续不断的挑战。然而,正是因为这些挑战,网络安全社区应运而生,成为从业者们互相交流、学习和…...

SAP MM学习笔记26- SAP中 振替转记(转移过账)和 在库转送(库存转储)5 - 总结
SAP 中在库移动 不仅有入库(GR),出库(GI),也可以是单纯内部的转记或转送。 1,振替转记(转移过账) 具体查看我之前的文章。 SAP MM学习笔记26- SAP中 振替转记ÿ…...

Stable Diffusion WebUI提示词Prompts常用推荐
在Stable Diffusion(以下简称SD)中,提示词是很重要的一部分,写好提示词就能让画图事半功倍,下面介绍一款好用的工具,能很程度上让你更轻松。 他就是sd-webui-prompt-all-in-one 下面将详细介绍的安装以及使用,后面将详细讲解提示词(Prompt)应该如何写提示词才能使画…...

Android 13 Ethernet变更
Android13 有线变更 以太网相关的功能在Android12 和13 网络部分变化是不大的,Android11 到Android 12 网络部分无论是代码存放目录和代码逻辑都是有较多修改的,主要包括以下几个部分 限制了设置有线网参数设置接口方法 新增有线网开启关闭接口方法 新…...

基于单片机的超声波语音测距系统
一、系统方案 超声波具有指向性强,能量消耗缓慢,在介质中传播的距离较远,因而超声波经常用于距离的测量,如测距仪和物位测量仪等都可以通过超声波来实现。利用超声波检测往往比较迅速、方便、计算简单、易于做到实时控制ÿ…...

算法系列-力扣876-求链表的中间节点
# 求链表中间节点,如果有两个中间节点取后面那个 链表定义 // lc codestart /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val val; } * …...

SpringBoot集成Redis、Redisson保姆教程【附源码】
1. SpringBoot集成Redis 关于Redis的安装,这里就不重复介绍了,需要的朋友可以看我之前的博文Redis多系统安装(Windows、Linux、Ubuntu) Redis原生命令大全,作者整理的很详细,大部分命令转化为java命令基本也是关键词 Redis 命令参考 接下来开始我们的正题,一起学习下…...

c++多线程中常用的使用方法
1)promise(保证)和future的联合使用,实现两个线程的数据传递 #include <iostream> #include<thread> #include<future>using namespace std;//promise用法:可以给线程一个值,而从另一个线程读出该值 // 实现了两个线程的数…...

【dart】dart基础学习使用(一):变量、操作符、注释和库操作
前言 学习dart语言。 注释 Dart 支持单行注释、多行注释和文档注释。 单行注释 单行注释以 // 开头。Dart 编译器将忽略从 // 到行尾之间的所有内容。 void main() {// 这是单行注释print(Welcome to my Llama farm!); }多行注释 多行注释以 /* 开始,以 / 结…...

element-plus 设置 el-date-picker 弹出框位置
前言 概述:el-date-picker 组件会自动根据空间范围进行选择比较好的弹出位置,但特定情况下,它自动计算出的弹出位置并不符合我们的实际需求,故需要我们手动设置。 存在的问题:element-plus 中 el-date-picker 文档中并…...

C++day7(auto关键字、lambda表达式、C++中的数据类型转换、C++标准模板库(STL)、list、文件操作)
一、Xmind整理: 关键词总结: 二、上课笔记整理: 1.auto关键字 #include <iostream>using namespace std;int fun(int a, int b, float *c, char d, double *e,int f) {return 12; }int main() {//定义一个函数指针,指向fu…...

纽扣电池/锂电池UN38.3安全检测报告
根据规章要求,航空公司和机场货物收运部门应对锂电池进行运输文件审查,重要的是每种型号的锂电池UN38.3安全检测报告。该报告可由的三方检测机构。如不能提供此项检测报告,将禁止锂电池进行航空运输. UN38.3包含产品:1、 锂电池2…...

K8S:K8S自动化运维容器Docker集群
文章目录 一.k8s概述1.k8s是什么2.为什么要用K8S3.作用及功能4.k8s容器集群管理系统 二.K8S的特性1.弹性伸缩2.自我修复3.服务发现和复制均衡4.自动发布和回滚5.集中化配置管理和秘钥管理6.存储编排7.任务批量处理运行 三.K8S的集群架构四.K8S的核心组件1.Master组件࿰…...

Java的guava 限流写法
第一步先引入 maven <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.0.1-jre</version> </dependency> 然后上方法 private final double rateLimiter10 1.0 / 10.0; // 每…...

[uniapp] scroll-view 简单实现 u-tabbar效果
文章目录 方案踩坑1.scroll-view 横向失败2.点击item不滚动?3. scrollLeft从哪里来? 效果图 方案 官方scroll-view 进行封装 配合属性 scroll-left Number/String 设置横向滚动条位置 即可 scroll-into-view 属性尝试过,方案较难实现 踩坑 1.scroll-view 横向失败 安装…...

vue常见问题汇总
来源:https://www.fly63.com/ Q1:安装超时(install timeout) 方案有这么些: cnpm : 国内对npm的镜像版本/*cnpm website: https://npm.taobao.org/*/npm install -g cnpm --registryhttps://registry.npm.taobao.org// cnpm 的大多命令跟 npm 的是一致的…...

GPT-3在化学中进行低数据发现是否足够?
今天介绍一份洛桑联邦理工学院进行的工作,这份工作被发表在化学期刊预印本网站上。 对于这份工作,有兴趣的朋友可以通过我们的国内ChatGPT镜像站进行测试使用,我们的站点并没有针对特定任务进行建设,是通用性质的。 化学领域进行…...

gitlab升级
1.下载需要的版本 wget -c https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-15.7.6-ce.0.el7.x86_64.rpm --no-check-certificate gitlab-ce-15.4.6-ce.0.el7.x86_64.rpm gitlab-ce-15.7.6-ce.0.el7.x86_64.rpm gitlab-ce-15.9.7-ce.0.el7.x86_64.rpm g…...

Matlab图像处理-灰度插值法
最近邻法 最近邻法是一种最简单的插值算法,输出像素的值为输入图像中与其最邻近的采样点的像素值。是将(u0,v0)(u_0,v_0)点最近的整数坐标u,v(u,v)点的灰度值取为(u0,v0)(u_0,v_0)点的灰度值。 在(u0,v0)(u_0,v_0)点各相邻像素间灰度变化较小时,这种方…...

axios 或 fetch 如何实现对发出的请求的终止?
终止 HTTP 请求是一个重要的功能,特别是在需要优化性能、避免不必要的请求或在某些事件发生时(例如用户点击取消)中断正在进行的请求时。以下是如何使用 axios 和 fetch 实现请求终止的方法: 1. axios axios 使用了 CancelToken…...

ChatGPT Prompting开发实战(四)
一、chaining prompts应用解析及输出文本的设定 由于输入和输出都是字符串形式的自然语言,为了方便输入和输出信息与系统设定使用的JSON格式之间进行转换,接下来定义从输入字符串转为JSON list的方法: 定义从JSON list转为输出字符串的方法&…...