设计模式-6--装饰者模式(Decorator Pattern)

news2024/11/23 8:40:21

一、什么是装饰者模式(Decorator Pattern)

装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不修改现有对象的情况下,动态地将新功能附加到对象上。这种模式通过创建一个包装类,即装饰者,来包含原始对象,并在其上添加额外的行为或功能。这样,你可以在运行时选择不同的装饰者组合来实现不同的功能组合。

装饰者模式的关键思想是将功能细分为一系列小的组件,然后将这些组件通过装饰者按照需要进行组合。这种模式遵循开放-关闭原则,即对扩展开放,对修改关闭。

主要角色:

  1. 组件(Component): 定义了一个抽象接口,可以是具体组件和装饰者共同实现的接口,表示被装饰者的基本功能。
  2. 具体组件(Concrete Component): 实现了组件接口的具体对象,即被装饰的原始对象。
  3. 装饰者(Decorator): 保持一个指向组件对象的引用,并实现与组件接口相同的接口。它可以有多个具体装饰者的子类。
  4. 具体装饰者(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++实现装饰者模式,动态地为对象添加功能。

三、使用装饰者模式需要注意的问题

在使用装饰者模式时,需要注意以下几个问题:

  1. 类爆炸: 装饰者模式可能会引入大量的小类,每个装饰者都是一个单独的类。这可能会导致类的数量急剧增加,增加代码复杂性和维护成本。因此,在选择使用装饰者模式时,需要仔细权衡增加的类数量是否值得所提供的灵活性和扩展性。
  2. 装饰者顺序: 装饰者模式中,装饰者的顺序可能会影响最终的对象组合。你需要确保装饰者的顺序不会引起意外的行为,特别是在组合多个装饰者时。
  3. 代码可读性: 过度使用装饰者模式可能会使代码变得难以理解和维护。因为每个具体装饰者只负责添加一小部分功能,当功能需要嵌套多层装饰者时,代码可能会变得冗长且难以阅读。
  4. 接口一致性: 在创建装饰者时,需要确保它们与组件(基类)具有一致的接口。这样,装饰者才能无缝地替代组件,而不会引发类型不匹配的问题。
  5. 不适合所有情况: 装饰者模式适用于需要动态地添加功能的情况。如果功能不太可能改变,或者只有固定数量的组合方式,那么使用装饰者模式可能会过于复杂,不切实际。
  6. 继承和组合的选择: 在设计时,需要权衡是否使用继承或组合。装饰者模式使用了组合,但过多的组合也可能使系统变得复杂。在一些情况下,简单的继承可能更合适。
  7. 性能影响: 使用装饰者模式可能会在运行时引入一些额外的开销,因为每个装饰者都会对对象进行包装和处理。这可能会在需要高性能的场景下造成问题。

总之,在使用装饰者模式时,需要根据实际情况谨慎权衡,考虑其带来的灵活性和复杂性,确保模式的应用不会导致代码难以维护或性能下降。

在这里插入图片描述

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

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

相关文章

排序之交换排序

文章目录 前言一、冒泡排序1、冒泡排序基本思想2、冒泡排序的效率 二、快速排序 -- hoare版本1、快速排序基本思想2、快速排序代码实现3、为什么最左边值做key时&#xff0c;右边先走 三、快速排序 -- 挖坑法1、快速排序 -- 挖坑法基本思想2、快速排序 -- 挖坑法代码实现3、为什…

stable diffusion实践操作-随机种子seed

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、seed是什么&#xff1f;二、使用步骤1.多批次随机生成多张图片2.提取图片seed3. 根据seed 再次培养4 seed使用4.1 复原别人图4.1 轻微修改 三、差异随机种子1. webUI位置2. 什么是差异随机种子3.使用差异…

找redis大key工具rdb_bigkeys

github官网 https://github.com/weiyanwei412/rdb_bigkeys 在centos下安装go [roothadoop102 rdb_bigkeys-master]# wget https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz [roothadoop102 rdb_bigkeys-master]# tar -zxf go1.13.5.linux-amd64.tar.gz -C /usr/local将g…

安装bpftrace和bcc的踩坑记录

最后在Ubuntu22.04使用Ubuntu提供的安装命令完成了安装。这里是记录尝试在Ubuntu18.04和Ubuntu22.04使用源码安装未果的过程。 文章目录 22版本安装bcc准备工具安装命令使用报错&#xff1a;iovisor封装的安装方式ubuntu的安装方式 For Bionic (18.04 LTS)官方提供的源码安装准…

SpringCloudGateway集成SpringDoc

SpringCloudGateway集成SpringDoc 最近在搞Spring版本升级&#xff0c;按客户要求升级Spring版本&#xff0c;原来用着SpringBoot 2.2.X版本&#xff0c;只需要升级SpringBoot 2.X最新版本也就可以满足客户Spring版本安全要求&#xff0c;可是好像最新的SpringBoot 2.X貌似也不…

Laravel chunk和chunkById的坑

在编写定时任务脚本的时候&#xff0c;经常会用到chunk和chunkById的API。 一、前言 数据库引擎为innodb。 表结构简述&#xff0c;只列出了本文用到的字段。 字段类型注释idint(11)IDtypeint(11)类型mark_timeint(10)标注时间&#xff08;时间戳&#xff09; 索引&#x…

手撕 视觉slam14讲 ch13 代码(1)工程框架与代码结构

在学习slam一年之后开始&#xff0c;开始自己理思路&#xff0c;全手敲完成ch13的整个代码 我们按照自己写系统的思路进行&#xff0c;首先确定好SLAM整体系统的流程&#xff0c;见下图&#xff0c;输入为双目图像&#xff0c;之后进入前端位姿估计和后端优化&#xff0c;中间…

滑动窗口实例3(最大连续1的个数Ⅲ)

题目&#xff1a; 给定一个二进制数组 nums 和一个整数 k&#xff0c;如果可以翻转最多 k 个 0 &#xff0c;则返回 数组中连续 1 的最大个数 。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1,0,0,0,1,1,1,1,0], K 2 输出&#xff1a;6 解释&#xff1a;[1,1,1,0,0,1,1…

stable diffusion实践操作-宽高设置以及高清修复

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、SD宽高怎么设置&#xff1f;1.1 宽高历史 二、高清修复总结 前言 主要介绍SD的宽高设置以及高清修复 一、SD宽高怎么设置&#xff1f; 1.1 宽高历史 SD生成256256图片效果最好。512512是SD一直使用的画…

【管理运筹学】第 7 章 | 图与网络分析(1,图论背景以及基本概念、术语)

文章目录 引言一、图与网络的基本知识1.1 图与网络的基本概念1.1.1 图的定义1.1.2 图中相关术语1.1.3 一些特殊图类1.1.4 图的运算 写在最后 引言 按照正常进度应该学习动态规划了&#xff0c;但我想换换口味&#xff0c;而且动态规划听说也有一定难度&#xff0c;还不一定会考…

设计模式—简单工厂

目录 一、前言 二、简单工厂模式 1、计算器例子 2、优化后版本 3、结合面向对象进行优化&#xff08;封装&#xff09; 3.1、Operation运算类 3.2、客户端 4、利用面向对象三大特性&#xff08;继承和多态&#xff09; 4.1、Operation类 4.2、加法类 4.3、减法类 4…

VTK——使用ICP算法进行模型配准

ICP算法 迭代最近点&#xff08;Iterative Closest Point&#xff0c;ICP&#xff09;算法是一种用于两个三维形状之间几何对齐&#xff08;也叫做配准&#xff09;的计算方法。通常&#xff0c;这两个形状至少有一个是点云数据。ICP算法用于最小化源点云与目标点云之间点到点…

【设计模式】Head First 设计模式——构建器模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点&#xff0c;然后分离它们&#xff0c;从而管理变化。将变化像小兔子一样关到笼子里&#xff0c;让它在笼子里随便跳&#xff0c;而不至于跳出来把你整个房间给污染掉。 设计思想 ​ 将一个复杂对象的构建与其表示相分离&…

【两个有序数组合并】

问题描述: 给定两个有序整数数组 A 和 B&#xff0c;将B合并到A中&#xff0c;使得 A 成为一个有序数组。 说明: 初始化 A 和 B 的元素数量分别为 m 和 n。A有足够的空间&#xff08;空间大小大于或等于 m n&#xff09;来保存 B 中的元素。默认升序。 输入输出描述&#xf…

大数据组件-Flume集群环境的启动与验证

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…

《YOLOv5:从入门到实战》专栏介绍 专栏目录

&#x1f31f;YOLOv5&#xff1a;从入门到实战 | 目录 | 使用教程&#x1f31f; 本专栏涵盖了丰富的YOLOv5算法从入门到实战系列教程&#xff0c;专为学习YOLOv5的同学而设计&#xff0c;堪称全网最详细的教程&#xff01;该专栏从YOLOv5基础知识入门到项目应用实战都提供了详细…

JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章

JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章 xxl-job概述windows部署调度中心docker部署调度中心 xxl-job入门案例xxl-job分片广播热点文章定时计算思路分析具体实现热文章计算定时计算 查询文章接口改造来源Gitee xxl-job概述 windows部署调度中心 运行 xxl-job\do…

【数据结构】队列---C语言版(详解!!!)

文章目录 &#x1f438;一、队列的概念及结构&#x1f344;1、队列的概念定义&#x1f344;2、动图演示 &#x1f438;二、队列的实现&#x1f438;三、链表结构队列详解&#x1f34e;创建队列的结构⭕接口1&#xff1a;定义结构体&#xff08;QNode、Queue&#xff09;⭕接口2…

LeetCode 23 合并 K 个升序链表

LeetCode 23 合并 K 个升序链表 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/merge-k-sorted-lists/description/ 博主Github&#xff1a;https://github.com/GDUT-Rp/LeetCode 题目&#xff1a; 给你一个链表数组…

中心差分法-学习笔记《结构动力学-陈政清》

激励分段解析法仅仅对外载荷进行了离散&#xff0c;但对运动方程还是严格满足的&#xff0c;体系的运动在时间轴上依然是满足运动微分方程。然而&#xff0c;一般的时域逐步积分法进一步放松要求&#xff0c;不仅仅对外荷载进行离散化处理&#xff0c;也对体系的运动进行离散化…