装饰器模式(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;允许你通过…

【C#】int? , C# 中的可空类型(Nullable Types)

在 C# 中&#xff0c;问号&#xff08;?&#xff09;用于表示可空类型&#xff08;nullable types&#xff09;。在你的代码中&#xff0c;int? 表示的是可空的整数类型&#xff0c;也就是可以存储 int 类型的值&#xff0c;也可以存储 null。具体来说&#xff1a; int? 详…

[小白系列]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…

在Spring Boot项目中整合Redis:高效数据存储与缓存的最佳实践

目录 1. 引入依赖 2. 创建序列化配置类 2.1 序列化的选择 3. 配置YAML文件 3.1 连接池的配置 4. 使用Redis 4.1 复杂数据类型的存储 4.2 列表、集合和哈希的使用 4.2.1 列表示例 4.2.2 集合示例 4.2.3 哈希示例 5. 处理事务和管道 5.1 事务示例 5.2 管道示例 6…

嵌入式硬件设计 — 智能设备背后的隐形架构大师

目录 引言 一、嵌入式硬件设计概述 &#xff08;一&#xff09;需求分析 &#xff08;二&#xff09;硬件选型 &#xff08;三&#xff09;电路设计 &#xff08;四&#xff09;PCB 制作与焊接 &#xff08;五&#xff09;硬件调试与测试 &#xff08;六&#xff09;软…

调度系统:使用 Airflow 对 Couchbase 执行 SQL 调度时的潜在问题

使用 Airflow 对 Couchbase 执行 SQL 调度时&#xff0c;通常情况下不会直接遇到与 Couchbase 分布式特性相关的异常&#xff0c;但在某些特定情境下&#xff0c;可能会出现一些与分布式环境、调度和数据一致性相关的潜在问题。以下是一些可能会遇到的问题和建议的解决方案&…

[大数据]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…

本题要求采用选择法排序,将给定的n个整数从大到小排序后输出。

#include <stdio.h> #define MAXN 10 int main() { int i, index, k, n, temp; int a[MAXN]; scanf("%d", &n); for (i 0; i < n; i) { scanf("%d", &a[i]); } // 外层循环控制排序轮数&#xff0c;一共需要n-1轮 for (k 0; k < n…

Vue.js的生命周期

Vue.js 是一个构建用户界面的渐进式框架&#xff0c;它提供了一个响应式和组件化的方式来构建前端应用。了解 Vue 的生命周期对于开发者来说至关重要&#xff0c;因为它可以帮助我们更好地控制组件的状态和行为。本文将详细介绍 Vue 的生命周期&#xff0c;并提供相应的代码示例…

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;我还将提供…

【Hash Function and HashMap】

散列函数&#xff08;Hash Function&#xff09;是一种将任意大小的数据映射到固定大小值的函数。在 HashMap 中&#xff0c;它扮演着核心角色。让我详细解释&#xff1a; 散列函数基本原理 输入&#xff1a;任意类型的键&#xff08;key&#xff09;输出&#xff1a;固定大小…

【jvm】为什么要有GC

目录 1. 自动内存管理2. 提升程序稳定性3. 优化性能4. 跨平台能力5. 分代回收策略 1. 自动内存管理 1.JVM中的GC机制负责自动管理内存&#xff0c;这意味着开发人员不需要手动分配和释放内存。2.这一特性大大简化了Java程序的内存管理&#xff0c;降低了内存泄漏和内存溢出等问…

Python泛型编程:TypeVar和Generic详解 - 写给初学者的指南

Python泛型编程&#xff1a;TypeVar和Generic详解 - 写给初学者的指南 前言1. 为什么需要泛型&#xff1f;2. TypeVar&#xff1a;定义泛型类型变量3. Generic&#xff1a;创建泛型类4. 多个泛型类型变量5. 使用场景小结结语 前言 大家好&#xff01;今天我们来聊一聊Python中…

COUNT(*)、COUNT(1)、COUNT(某一列)的区别是什么?哪个性能更好

一些特殊情况&#xff1a; 有索引时&#xff1a;如果查询使用了索引&#xff0c;且查询的列在索引中&#xff0c;COUNT(某一列) 可能在某些情况下会比较快&#xff0c;因为数据库只需要扫描索引&#xff0c;而不需要扫描整个表。有 NULL 值时&#xff1a;COUNT(某一列) 可能会…