装饰器模式(Decorator Pattern)

装饰器模式(Decorator Pattern)


定义

装饰器模式是一种结构性设计模式,通过 动态组合对象 的方式,为对象添加额外功能,而无需修改原有类。


装饰器模式的核心思想
  1. 对象增强:在现有类的基础上动态添加功能,而不修改类的代码。
  2. 功能组合:通过多个装饰器的嵌套,可以灵活组合功能。
  3. 继承与组合
    • 继承是一种 静态扩展
    • 装饰器模式是一种 动态扩展

类结构

装饰器模式的类结构包含以下几部分:

  1. 抽象组件(Component)

    • 定义接口,声明核心功能方法。
    • 所有被装饰类和装饰器类都必须实现此接口。
  2. 具体组件(ConcreteComponent)

    • 实现抽象组件的接口,定义基本功能。
  3. 装饰器基类(Decorator)

    • 实现抽象组件接口。
    • 持有一个组件的引用(指针),并通过组合扩展功能。
  4. 具体装饰器类(ConcreteDecorator)

    • 从装饰器基类派生。
    • 对原始功能进行增强。

装饰器模式与代理模式的区别
区别点装饰器模式代理模式
目的增强类的功能控制访问权限
实现的重点功能扩展权限控制
类的设计装饰器类持有被装饰对象的指针代理类持有被代理对象的指针
调用顺序递归调用,逐层增强功能代理类决定是否调用实际方法

应用场景
  1. 需要动态扩展功能:例如,添加日志、权限验证等。
  2. 功能可以被多次组合:如 GUI 控件系统中的多种视觉效果。
  3. 避免类爆炸:避免因子类过多导致复杂的继承体系。

优缺点

优点

  1. 动态扩展对象功能,避免继承的静态绑定。
  2. 可以组合多个装饰器,灵活性高。
  3. 符合开闭原则。

缺点

  1. 需要创建大量的小类,可能会增加系统复杂性。
  2. 调试较为复杂,特别是多个装饰器嵌套时。

代码实现

需求:以汽车为例,实现动态添加 定速巡航自动刹车车道偏离预警 三种功能。


完整代码
#include <iostream>
#include <string>// 抽象组件
class Car {
public:virtual void show() = 0; // 显示汽车配置virtual ~Car() = default;
};// 具体组件:宝马
class BMW : public Car {
public:void show() override {std::cout << "This is a BMW car with basic configuration.\n";}
};// 具体组件:奥迪
class Audi : public Car {
public:void show() override {std::cout << "This is an Audi car with basic configuration.\n";}
};// 具体组件:奔驰
class Benz : public Car {
public:void show() override {std::cout << "This is a Benz car with basic configuration.\n";}
};// 抽象装饰器
class CarDecorator : public Car {
protected:Car* car; // 持有被装饰的对象
public:CarDecorator(Car* c) : car(c) {}void show() override {car->show(); // 调用被装饰对象的 show 方法}virtual ~CarDecorator() {delete car;}
};// 具体装饰器 1:定速巡航
class CruiseControl : public CarDecorator {
public:CruiseControl(Car* c) : CarDecorator(c) {}void show() override {CarDecorator::show();std::cout << " + Added feature: Cruise Control.\n";}
};// 具体装饰器 2:自动刹车
class AutomaticBraking : public CarDecorator {
public:AutomaticBraking(Car* c) : CarDecorator(c) {}void show() override {CarDecorator::show();std::cout << " + Added feature: Automatic Braking.\n";}
};// 具体装饰器 3:车道偏离预警
class LaneDepartureWarning : public CarDecorator {
public:LaneDepartureWarning(Car* c) : CarDecorator(c) {}void show() override {CarDecorator::show();std::cout << " + Added feature: Lane Departure Warning.\n";}
};// 主函数
int main() {// 创建一个基础 BMW 对象Car* bmw = new BMW();// 给 BMW 添加定速巡航功能bmw = new CruiseControl(bmw);// 再添加自动刹车功能bmw = new AutomaticBraking(bmw);// 最后添加车道偏离预警功能bmw = new LaneDepartureWarning(bmw);// 显示 BMW 的完整配置bmw->show();// 释放内存delete bmw;return 0;
}

输出结果
This is a BMW car with basic configuration.+ Added feature: Cruise Control.+ Added feature: Automatic Braking.+ Added feature: Lane Departure Warning.

代码解析
  1. 抽象组件 Car

    • 提供统一的接口,定义所有汽车共有的功能。
  2. 具体组件

    • 例如 BMWAudiBenz,实现基本功能。
  3. 抽象装饰器 CarDecorator

    • 持有一个 Car 指针,用于动态装饰功能。
  4. 具体装饰器

    • 每个具体装饰器类实现独特的功能,如 CruiseControlAutomaticBraking
  5. 动态组合

    • 将多个装饰器嵌套在一起,实现功能的动态组合。

总结
  1. 装饰器模式使得对象功能扩展变得灵活,避免了继承的复杂性。
  2. 通过组合的方式,可以动态添加功能,减少子类数量,降低维护成本。
  3. 在实际开发中,装饰器模式非常适合需要动态扩展功能的场景,如 GUI 开发、日志记录、权限验证等。

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

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

相关文章

【SH】微信小程序调用EasyDL零门槛AI开发平台的图像分类研发笔记

文章目录 微信小程序字符串字符串模板字符串拼接 上传图片编写JS代码编写wxml代码编写wxss代码 GET请求测试编写测试代码域名不合法问题 GET和POST请求测试编写JS代码编写wxml代码编写wxss代码 效果展示 微信小程序字符串 字符串模板 这是ES6引入的特性&#xff0c;允许你通过…

[小白系列]Ubuntu安装教程-安装prometheus和Grafana

Docker安装prometheus 拉取镜像 docker pull prom/prometheus 配置文件prometheus.yml 在/data/prometheus/建立prometheus.yml配置文件。&#xff08;/data/prometheus/可根据自己需要调整&#xff09; global:scrape_interval: 15s # By default, scrape targets ev…

[大数据]Hudi编译集成

1. Hudi概述 1.1 Hudi简介 What is Apache Hudi Apache Hudi is the next generation streaming data lake platform. Apache Hudi brings core warehouse and database functionality directly to a data lake. Hudi provides tables, transactions, efficient upserts/dele…

windows下 mysql开启 binlog日志

一、查看是否开启 binlog -- 方式一 show binary logs;-- 方式二 show VARIABLES like log_bin 说明没有开启 方式一 &#xff1a;you are not using binary logging 方式二&#xff1a;log_bin off 二、编辑 my.ini 配置文件 默认安装地点位于&#xff1a;C:\ProgramDat…

Java-22 深入浅出 MyBatis - 手写ORM框架3 手写SqlSession、Executor 工作原理

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

Android 逆向/反编译/Hook修改应用行为 基础实现

前言&#xff1a;本文通过一个简单的情景案例实现安卓逆向的基本操作 一、情景描述 本文通过一个简单的情景案例来实现安卓逆向的基本操作。在这个案例中所使用的项目程序是我自己的Demo程序&#xff0c;不会造成任何的财产侵害&#xff0c;本文仅作为日常记录及案例分享。实…

IDEA创建Spring Boot项目配置阿里云Spring Initializr Server URL【详细教程-轻松学会】

1.首先打开idea选择新建项目 2.选择Spring Boot框架(就是选择Spring Initializr这个) 3.点击中间界面Server URL后面的三个点更换为阿里云的Server URL Idea中默认的Server URL地址&#xff1a;https://start.spring.io/ 修改为阿里云Server URL地址&#xff1a;https://star…

基于MATLAB的信号处理工具:信号分析器

信号&#xff08;或时间序列&#xff09;是与特定时间相关的一系列数字或测量值&#xff0c;不同的行业和学科将这一与时间相关的数字序列称为信号或时间序列。生物医学或电气工程师会将其称为信号&#xff0c;而统计学家或金融定量分析师会使用时间序列这一术语。例如&#xf…

Plugin - 插件开发03_Spring Boot动态插件化与热加载

文章目录 Pre方案概览使用插件的好处流程CodePlugin 定义Plugin 实现Plugin 使用方动态加载插件类加载器注册与卸载插件配置文件启动类测试验证 小结 Pre 插件 - 通过SPI方式实现插件管理 插件 - 一份配置&#xff0c;离插件机制只有一步之遥 插件 - 插件机制触手可及 Plug…

ECharts柱状图-阶梯瀑布图,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个柱状图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供…

C/C++流星雨

系列文章 序号直达链接1C/C爱心代码2C/C跳动的爱心3C/C李峋同款跳动的爱心代码4C/C满屏飘字表白代码5C/C大雪纷飞代码6C/C烟花代码7C/C黑客帝国同款字母雨8C/C樱花树代码9C/C奥特曼代码10C/C精美圣诞树11C/C俄罗斯方块12C/C贪吃蛇13C/C孤单又灿烂的神-鬼怪14C/C闪烁的爱心15C/C…

ModelScope-Agent(1): 基于开源大语言模型的可定制Agent系统

目录 简介快速入门 简介 github地址 快速入门 看前两篇&#xff0c;调用千问API和天气API # 选用RolePlay 配置agent from modelscope_agent.agents.role_play import RolePlay # NOQArole_template 你扮演一个天气预报助手&#xff0c;你需要查询相应地区的天气&#x…

【模型对比】ChatGPT vs Kimi vs 文心一言那个更好用?数据详细解析,找出最适合你的AI辅助工具!

在这个人工智能迅猛发展的时代&#xff0c;AI聊天助手已经深入我们的工作与生活。你是否曾在选择使用ChatGPT、Kimi或是百度的文心一言时感到一头雾水&#xff1f;每款AI都有其独特的魅力与优势&#xff0c;那么&#xff0c;究竟哪一款AI聊天助手最适合你呢&#xff1f;本文将带…

微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算

微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…

SQL——DQL分组聚合

分组聚合&#xff1a; 格式&#xff1a; select 聚合函数1(聚合的列),聚合函数2(聚合的列) from 表名 group by 标识列; ###若想方便分辨聚合后数据可在聚合函数前加上标识列&#xff08;以标识列进行分组&#xff09; 常见的聚合函数: sum(列名):求和函数 avg(列名)…

maven打包时出现找不到符号的错误如何解决

在maven打包的时候有时会出现找不到符号的情况&#xff0c;具体原因是由于引用的BaseEntity是framework模块下的实体类&#xff0c;所以需要将framework重新clean再install&#xff0c;成功后再将我们的模块打包就成功了

openGauss开源数据库实战二十一

文章目录 任务二十一 使用JDBC访问openGauss数据库任务目标实施步骤一、准备工作 二、下载并安装JavaSE81 下载JavaSE8安装Java8SE并配置环境变量 三、下载并安装eclipse四、下载并安装openGauss的JDBC驱动包五、使用IDEA编写JDBC测试程序1 使用IDEA的SSH连接虚拟机2 创建项目并…

Git:常用命令

一、查看当前分支 git branch 二、查看所有分支 git branch -a 三、切换到远程分支 git checkout origin/分支名 示例&#xff1a;git checkout origin/dev 四、拉取远程分支代码 git pull origin 分支名 示例&#xff1a;git pull origin dev 五、常用指令 查看暂存区…

运维实战:K8s 上的 Doris 高可用集群最佳实践

今天我们将深入探讨&#xff1a;&#xff1a;如何在 K8s 集群上部署 Compute storage coupled&#xff08;存算耦合&#xff09; 模式的 Doris 高可用集群&#xff1f; 本文&#xff0c;我将为您提供一份全面的实战指南&#xff0c;逐步引导您完成以下关键任务&#xff1a; 配…

在GITHUB上传本地文件指南(详细图文版)

这份笔记简述了如何在GITHUB上上传文件夹的详细策略。 既是对自己未来的一个参考&#xff0c;又希望能给各位读者带来帮助。 详细步骤 打开目标文件夹&#xff08;想要上传的文件夹&#xff09; 右击点击git bash打开 GitHub创立新的仓库后&#xff0c;点击右上方CODE绿色按…