装饰器设计模式学习

来自chatgpt

1.介绍

装饰器设计模式(Decorator Pattern)是一种结构型设计模式,允许你通过将对象包装在一个装饰器类中来动态地为对象添加新的功能。装饰器模式通常用于当需要扩展一个类的功能时,而不需要修改该类的源代码。它通过创建一个装饰器类来实现这一目标,并且可以将多个装饰器链式组合

装饰器模式的关键组成部分:

  1. Component(组件): 一个接口或抽象类,定义了被装饰对象的标准行为。
  2. ConcreteComponent(具体组件): 实现了Component接口的具体类,表示被装饰的对象。
  3. Decorator(装饰器): 一个实现了Component接口的抽象类,它持有一个Component对象并委托所有行为给它
  4. ConcreteDecorator(具体装饰器): 装饰器类的具体实现,它在调用委托的行为之前或之后执行额外的功能。

例子:

#include <iostream>
#include <string>// Component接口
class Car {
public:virtual ~Car() = default;virtual std::string getDescription() const = 0;virtual double cost() const = 0;
};// ConcreteComponent:基础的Car类
class BasicCar : public Car {
public:std::string getDescription() const override {return "Basic Car";}double cost() const override {return 20000.0;}~BasicCar(){std::cout << "Deleting BasicCar" << std::endl;}
};// Decorator基类,需要继承Car类
class CarDecorator : public Car {
protected:Car* car;
public:CarDecorator(Car* c) : car(c) {}virtual ~CarDecorator() { std::cout << "Deleting CarDecorator" << std::endl;delete car; }
};// ConcreteDecorator:添加空调功能
class WithAirConditioning : public CarDecorator {
public:WithAirConditioning(Car* c) : CarDecorator(c) {}std::string getDescription() const override {return car->getDescription() + " with Air Conditioning";}double cost() const override {return car->cost() + 1500.0;}~WithAirConditioning() {std::cout << "Deleting WithAirConditioning" << std::endl;}
};// ConcreteDecorator:添加天窗功能
class WithSunroof : public CarDecorator {
public:WithSunroof(Car* c) : CarDecorator(c) {}std::string getDescription() const override {return car->getDescription() + " with Sunroof";}double cost() const override {return car->cost() + 1200.0;}~WithSunroof() {std::cout << "Deleting WithSunroof" << std::endl;}
};int main() {Car* myCar = new BasicCar();std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;myCar = new WithAirConditioning(myCar);std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;myCar = new WithSunroof(myCar);std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;delete myCar; // 删除装饰器时会自动删除基本车对象return 0;
}// 运行结果
Basic Car costs $20000
Basic Car with Air Conditioning costs $21500
Basic Car with Air Conditioning with Sunroof costs $22700
Deleting WithSunroof
Deleting CarDecorator
Deleting WithAirConditioning
Deleting CarDecorator
Deleting BasicCar

2.装饰器基类可以不继承组件基类吗

在装饰器模式中,CarDecorator 必须实现 Car 接口(或继承 Car 基类),否则无法保证装饰器与被装饰对象的行为一致性。这是一种模式的核心要求:装饰器与被装饰对象应该共享相同的接口

具体原因如下:

  1. 实现统一的接口
    通过实现 Car 接口,装饰器可以被视为一种特殊类型的 Car,从而在程序中保持一致的处理方式。客户端代码不需要知道具体是 Car 还是装饰器,依然可以调用 getDescription()cost() 等方法。

  2. 支持递归包装
    如果装饰器不实现 Car 接口,无法递归地嵌套装饰器。每个装饰器必须具有相同的接口,才能被进一步装饰。

如果不继承的话,就不支持装饰器嵌套递归。

#include <iostream>
#include <string>class Car {
public:virtual ~Car() = default;virtual std::string getDescription() const = 0;virtual double cost() const = 0;
};class BasicCar : public Car {
public:std::string getDescription() const override {return "Basic Car";}double cost() const override {return 20000.0;}
};// Decorator没有继承Car
class WithAirConditioning {
private:Car* car;
public:WithAirConditioning(Car* c) : car(c) {}std::string getDescription() const {return car->getDescription() + " with Air Conditioning";}double cost() const {return car->cost() + 1500.0;}
};int main() {Car* myCar = new BasicCar();std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;WithAirConditioning acDecorator(myCar);std::cout << acDecorator.getDescription() << " costs $" << acDecorator.cost() << std::endl;// 想进一步装饰为“加装天窗”的车,但WithAirConditioning无法作为Car传入:// WithSunroof sunroofDecorator(&acDecorator); // 错误,因为acDecorator不是Car类型delete myCar;return 0;
}

上述代码有两个问题:

  1. 无法递归嵌套装饰器WithAirConditioning 不是 Car 类型,不能进一步用其他装饰器包装。
  2. 客户端代码复杂:需要额外处理 WithAirConditioning 的接口,且不能直接将它作为一个通用的 Car 来操作。

3.对象都是如何释放的?

CarDecorator中删除了被包装的对象car。

因此,当我们删除最外层装饰器(WithSunroof)时:

  1. WithSunroof 的析构函数会调用其基类 CarDecorator 的析构函数。
  2. CarDecorator 的析构函数会 delete 它所包装的 WithAirConditioning 对象。
  3. 类似地,WithAirConditioning 的析构函数会继续调用 CarDecorator 的析构函数,最终删除 BasicCar 对象。

这种递归删除确保了所有层级的对象都被正确释放。

4.使用智能指针的版本

// 没太看懂这个版本的。

#include <iostream>
#include <memory>
#include <string>class Car {
public:virtual ~Car() = default;virtual std::string getDescription() const = 0;virtual double cost() const = 0;
};class BasicCar : public Car {
public:std::string getDescription() const override {return "Basic Car";}double cost() const override {return 20000.0;}
};class CarDecorator : public Car {
protected:std::unique_ptr<Car> car;
public:CarDecorator(std::unique_ptr<Car> c) : car(std::move(c)) {}virtual ~CarDecorator() = default;
};class WithAirConditioning : public CarDecorator {
public:WithAirConditioning(std::unique_ptr<Car> c) : CarDecorator(std::move(c)) {}std::string getDescription() const override {return car->getDescription() + " with Air Conditioning";}double cost() const override {return car->cost() + 1500.0;}
};class WithSunroof : public CarDecorator {
public:WithSunroof(std::unique_ptr<Car> c) : CarDecorator(std::move(c)) {}std::string getDescription() const override {return car->getDescription() + " with Sunroof";}double cost() const override {return car->cost() + 1200.0;}
};int main() {std::unique_ptr<Car> myCar = std::make_unique<BasicCar>();myCar = std::make_unique<WithAirConditioning>(std::move(myCar));myCar = std::make_unique<WithSunroof>(std::move(myCar));std::cout << myCar->getDescription() << " costs $" << myCar->cost() << std::endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/17869.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

从PE结构到LoadLibrary

从PE结构到LoadLibrary PE是Windows平台主流可执行文件格式,.exe , .dll, .sys, .com文件都是PE格式 32位的PE文件称为PE32&#xff0c;64位的称为PE32&#xff0c;PE文件格式在winnt.h头中有着详细的定义&#xff0c;PE文件头包含了一个程序在运行时需要的所有信息&#xff…

聚类分析 | MSADBO优化Spectral谱聚类优化算法

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于改进正弦算法引导的蜣螂优化算法(MSADBO)优化Spectral谱聚类&#xff0c;matlab代码&#xff0c;直接运行! 创新独家&#xff0c;先用先发&#xff0c;注释清晰&#xff0c;送MSADBO参考文献!优化参数 优化后的带…

【C++】构造与析构函数

目录&#xff1a; 一、 This指针  &#xff08;一&#xff09;使用方法&#xff1a; 二、类的默认成员函数 三、构造函数  &#xff08;一&#xff09;构造函数的特点 四、析构函数 &#xff08;一&#xff09;析构函数的特点 正文 一、 This指针 在c语言中我们调用函…

2021TCSVT,VDM-DA:面向无源数据域自适应的虚拟域建模

原文标题&#xff1a;VDM-DA: Virtual Domain Modeling for Source Data-free Domain Adaptation 中文标题&#xff1a;VDM-DA&#xff1a;面向无源数据域自适应的虚拟域建模 1、Abstract 领域适应旨在利用标签丰富的领域&#xff08;源领域&#xff09;来帮助标签稀缺领域&…

MySQL数据库1——数据库概论

一.数据库概论 1.数据库 数据库&#xff08;DataBase&#xff0c;DB&#xff09;&#xff1a;是长期存储在计算机内、有组织的、统一管理的相关数据的集合。简单来说&#xff0c;它就是一个存储各种数据的仓库&#xff0c;且存储过程不是随便而是有组织的。 数据库管理系统&am…

英伟达Tensor Core技术架构原理分析

英伟达Tensor Core架构技术原理 英伟达的Tensor Core架构是一种专为加速人工智能、深度学习、高性能计算(HPC)等领域中的矩阵运算和张量运算而设计的硬件单元。自首次在Volta架构中引入以来&#xff0c;Tensor Cores已成为NVIDIA高端GPU的核心特性&#xff0c;并在后续的Turing…

Linux基础5-进程控制1(fork创建子进程,写时拷贝,进程退出)

上篇文章&#xff1a;Linux基础4-进程5&#xff08;程序地址空间详解&#xff09;-CSDN博客 本篇重点&#xff1a;fork&#xff0c;写实拷贝&#xff0c;进程退出 目录 一. fork创建子进程 1.1 fork用法 1.2 fork返回值有两个的理解 二. 进程退出码 2.1 进程退出码 2.2 进…

用python中的tkinter包实现进度条

python中的tkinter包是一种常见的设计程序的GUI界面用的包。本文主要介绍这里面的一个组件&#xff1a;进度条&#xff08;Progressbar&#xff09;。Tkinter Progressbar里面对进度条组件已经做了一定的介绍&#xff0c;但比较抽象。本文以另一种方式介绍这个组件及其常用用法…

20.使用标准差剔除异常值

标准差剔除异常值 1. 方法2. 示例代码2.1 数据读取与清洗2.2 分段读取数据并绘图2.3 解释2.4 outliers2.5 结果展示 我有个记录数据采集后格式是step_rewards.txt 的文档&#xff0c;里面只有一列数据&#xff0c;10*10000行数据&#xff0c;没有表头&#xff0c;分别代表奖励数…

中科蓝讯修改蓝牙名字:【图文讲解】

本文以市面上一款公板公模的畅销产品为例。K12蓝牙音响。 音响用的芯片是&#xff1a;AB5768E MIC用的芯片是&#xff1a;AB5769A 硬件框架图如下&#xff1a; 芯片修改名字&#xff0c;通过下载工具中的配置进行修改。选择蓝牙配置&#xff0c;然后会出现蓝牙名字&#xff…

旅行包发霉怎么处理 除霉及防霉解决方法

近些年听到很多箱包工厂的心声&#xff0c;为什么箱包旅行包每年都会出现长霉请况呢&#xff1f;长霉了&#xff0c;也就是长毛了&#xff0c;长出那些病菌、真菌、细菌等微生物。经ihaoer防霉人士介绍旅行包长霉处理方法如下&#xff1a; 旅行包长霉的因素 一、旅行包储存在阴…

14、交互补充

1、元素的三大系列 1.1、offset系列 1.1.1、offset初相识 使用offset系列相关属性可以动态的得到该元素的位置&#xff08;偏移&#xff09;、大小等 获得元素距离带有定位祖先元素的位置获得元素自身的大小&#xff08;宽度高度&#xff09;注意&#xff1a;返回的数值都不…

【IEEE出版、八大高校联合举办、稳定EI检索】第四届人工智能与智能制造国际研讨会(AIIM 2024,12月20-22日)

第四届人工智能与智能制造国际研讨会&#xff08;AIIM 2024&#xff09; The 4th International Symposium on Artificial Intelligence and Intelligent Manufacturing 2024年12月20-22日 中国成都 重要信息 大会官网&#xff1a;www.isaiim.com 大会时间&#xff1a;202…

朴素贝叶斯算法探讨与实践

引言 和撰写博文[1]的缘由一样&#xff0c;本文是想要在所创设的专栏[2]里把所谓的十大机器学习算法[3]全部过一遍。 朴素贝叶斯算法是传统机器学习里的一种可以被用来进行分类的算法&#xff0c;本文将对其原理进行说明&#xff0c;并基于原理给出一个基于该算法的分类实践。…

《数据在内存中的存储》

内存函数 1. 整数在内存中的存储 &#xff08;1&#xff09;旧识回顾&#xff1a; 之前在学到操作符的时候&#xff0c;我们就学过了下面的内容&#xff1a; 整数的二进制的表示方式有三种&#xff0c;原码、反码、补码 有符号的整数&#xff0c;三种表示方式均有符号位和数…

【路径规划】粒子群算法、遗传算法、差分进化算法、灰狼优化算法、麻雀优化算法(PSO、GA、DE、GWO、SSA)路径规划

摘要 本文探讨了多种智能优化算法在路径规划中的应用&#xff0c;包括粒子群算法&#xff08;PSO&#xff09;、遗传算法&#xff08;GA&#xff09;、差分进化算法&#xff08;DE&#xff09;、灰狼优化算法&#xff08;GWO&#xff09;和麻雀优化算法&#xff08;SSA&#x…

CSS基础知识05(弹性盒子、布局详解,动画,3D转换,calc)

目录 0、弹性盒子、布局 0.1.弹性盒子的基本概念 0.2.弹性盒子的主轴和交叉轴 0.3.弹性盒子的属性 flex-direction row row-reverse column column-reverse flex-wrap nowrap wrap wrap-reverse flex-dirction和flex-wrap的组合简写模式 justify-content flex-s…

如何搭建一台邮箱服务器,配置满分邮箱

如何搭建一台邮箱服务器,配置满分邮箱 搭建一台个人邮箱服务器听上去非常有技术含量&#xff0c;但只要准备工作充分&#xff0c;并且选择合适的软件&#xff0c;配置满分的邮箱&#xff0c;其实并没有想象中那么困难。在这篇文章中&#xff0c;我们将介绍搭建邮箱服务器的 必备…

DevOps工程技术价值流:打造卓越项目协作的优化宝典

一、引言 解锁项目协作的无限潜力&#xff0c;覆盖全链路实现流畅高效。 在当今瞬息万变的商业环境中&#xff0c;项目协作的效率和效果直接关系到企业的竞争力和市场响应速度。DevOps工程技术价值流中的项目协作优化&#xff0c;不仅是技术层面的革新&#xff0c;更是团队协…

【JAVA毕业设计】基于Vue和SpringBoot的冬奥会科普平台

本文项目编号 T 610 &#xff0c;文末自助获取源码 \color{red}{T610&#xff0c;文末自助获取源码} T610&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状 六、核心代码6.1 查询项目类型6.…