【第八节】C++设计模式(结构型模式)-Decorator(装饰器)模式

embedded/2025/3/1 10:03:00/

目录

一、问题引出

二、模式选择

三、代码实现

四、总结讨论


一、问题引出

        装饰器模式:动态扩展对象功能的设计模式

        在面向对象(OO)设计与开发中,我们常面临为已有类添加新职责的需求。传统方法是通过继承创建子类来实现功能扩展,但这种方式容易导致继承层次过深,显著增加系统复杂度。装饰器模式(Decorator Pattern)应运而生,其通过组合替代继承的机制,为功能扩展提供了更灵活的解决方案,从而避免了继承层次过深带来的复杂性。

二、模式选择

装饰器模式的典型结构图如下:

        在结构中,ConcreteComponent(具体组件)和 Decorator(装饰器)均继承自 Component 基类,共享统一接口。可能有人质疑:为何不直接让 Decorator 持有 ConcreteComponent 的指针来实现扩展?答案是此方式仅支持单一组件类型。若新增其他组件类型(如 AnotherConcreteComponent),则需重新定义新的装饰器类,违背开闭原则。而通过共享 Component 基类,装饰器可借助多态特性,适配所有子类对象,实现通用扩展能力。这正是装饰器模式的核心优势。

:若仅需为单一组件类型添加功能,可省略 Decorator 基类,直接实现具体装饰器。

三、代码实现

        装饰器模式的实现并不复杂,下面是一个完整的代码示例(采用 C++ 实现)。

代码片段 1:Decorator.h

#ifndef _DECORATOR_H_
#define _DECORATOR_H_// 抽象组件基类
class Component {
public:virtual ~Component() {}virtual void Operation() = 0;  // 纯虚接口
protected:Component() {}  // 允许子类构造
};// 具体组件类
class ConcreteComponent : public Component {
public:void Operation() override;  // 实现基类接口
};// 抽象装饰器基类
class Decorator : public Component {
public:Decorator(Component* com) : _com(com) {}virtual ~Decorator() { delete _com; }  // 管理组件生命周期void Operation() override;            // 委托给组件对象
protected:Component* _com;  // 组合的组件对象
};// 具体装饰器类
class ConcreteDecorator : public Decorator {
public:ConcreteDecorator(Component* com) : Decorator(com) {}void Operation() override;  void AddedBehavior();        // 新增扩展行为
};#endif //~_DECORATOR_H_

代码片段 2:Decorator.cpp

#include "Decorator.h"
#include <iostream>// 具体组件实现
void ConcreteComponent::Operation() {std::cout << "ConcreteComponent: 基础操作" << std::endl;
}// 装饰器默认实现(可省略)
void Decorator::Operation() {if (_com) _com->Operation();  // 委托调用
}// 具体装饰器扩展实现
void ConcreteDecorator::Operation() {Decorator::Operation();      // 调用原有功能AddedBehavior();             // 添加新行为
}void ConcreteDecorator::AddedBehavior() {std::cout << "ConcreteDecorator: 新增扩展行为" << std::endl;
}

代码片段 3:main.cpp

#include "Decorator.h"int main() {Component* component = new ConcreteComponent();  // 创建基础组件Component* decorated = new ConcreteDecorator(component);  // 动态装饰decorated->Operation();  // 执行扩展后的操作delete decorated;  // 释放资源(自动递归删除组件)return 0;
}

代码解析

组件与装饰器关系

        ConcreteComponent 实现基础功能,ConcreteDecorator 通过组合持有组件对象,并在其操作前后添加新行为。

        装饰器类继承自 Component,保证接口一致性,支持嵌套装饰(如DecoratorA(DecoratorB(Component)))。

生命周期管理

        装饰器负责管理其持有的组件对象(delete _com),客户端仅需释放最外层装饰器,避免内存泄漏。

输出结果
        ConcreteComponent: 基础操作
        ConcreteDecorator: 新增扩展行为

四、总结讨论

模式对比:装饰器 vs 代理 vs 组合

        若装饰器仅持有具体组件(非抽象接口),其结构将与代理模式高度相似,但两者意图截然不同。

        装饰器模式与组合模式(Composite Pattern)在结构上有些相似,但它们的主要区别在于应用场景和目的。装饰器模式与代理模式(Proxy Pattern)在某些方面也有相似之处。虽然它们在结构图上并不相似,但如果让 `Decorator` 直接持有一个 `ConcreteComponent` 的引用(指针),其结构图就与代理模式非常相似了。

        由此,装饰器模式与代理模式的相似之处在于,它们都通过组合的方式持有一个指向其他对象的引用(指针)。不同之处在于,代理模式通常会提供与其代理对象相同的接口,并将操作直接委托给代理对象执行。而装饰器模式则通过组合的方式动态地为对象添加新的职责。

        装饰器模式不仅通过组合的方式避免了继承带来的复杂性,还为设计提供了一种“即用即付”的方式来添加职责。在 OO 设计和分析中,常常会遇到这样的情况:为了多态性,通过父类指针指向其具体子类,但当具体子类需要添加新的职责时,就必须在父类中添加相应的抽象接口。这会导致父类承载过多的职责,并且所有子类都会继承这些接口,即使它们并不需要。装饰器模式通过动态添加职责的方式,很好地解决了这一问题。由此总结其核心优势与适用场景如下:

优势

        (1)动态扩展:运行时灵活添加功能,避免静态继承的臃肿。

        (2)接口一致性:装饰后对象仍为 Component 类型,兼容原有逻辑。

        (3)职责分离:每个装饰器仅关注单一扩展点,符合单一职责原则。

适用场景

        (1)需为对象添加可选或可拆卸功能(如日志、缓存、权限校验)。

        (2)无法通过继承扩展(如 final 类)或继承会导致类爆炸。

        装饰器模式通过组合+委托的机制,实现了对象功能的动态扩展。其核心在于:

        (1)开放-封闭原则:无需修改原有代码,通过新增装饰器扩展功能。

        (2)接口抽象:统一组件与装饰器的接口,支持多态嵌套。

        (3)灵活替代继承:避免深度继承层次,降低系统复杂度。

        该模式尤其适用于框架设计或需要高频扩展的场景,是面向对象设计中“组合优于继承”理念的经典实践。


http://www.ppmy.cn/embedded/169026.html

相关文章

MATLAB学习之旅:图像处理与计算机视觉应用

在前面的学习中&#xff0c;我们已经深入了解了MATLAB在数据建模与仿真方面的强大功能。从基础的数据处理到复杂的模型构建与仿真分析&#xff0c;MATLAB为我们提供了丰富的工具和函数&#xff0c;帮助我们解决各种实际问题。如今&#xff0c;我们将迈向下一个充满挑战与创新的…

【每日八股】Redis篇(二):数据结构

Redis 数据类型&#xff1f; 主要有 STRING、LIST、ZSET、SET 和 HASH。 STRING String 类型底层的数据结构实现主要是 SDS&#xff08;简单动态字符串&#xff09;&#xff0c;其主要应用场景包括&#xff1a; 缓存对象&#xff1a;可以用 STRING 缓存整个对象的 JSON&…

对于邮箱地址而言,短中划线(Hyphen, -)和长中划线(Em dash, —)有区别吗

对于邮箱地址而言&#xff0c;**短中划线&#xff08;Hyphen, -&#xff09;和长中划线&#xff08;Em dash, —&#xff09;**有明确的区别&#xff1a; 短中划线&#xff08;Hyphen, -&#xff09;&#xff1a; 在邮箱地址中&#xff0c;短中划线是可以使用的&#xff0c;通常…

Windows环境下SuperMapGIS 11i 使用达梦数据库

1. 环境介绍&#xff1a; 1.1. 操作系统&#xff1a; windows server 2019 1.2. GIS 软件&#xff1a; 1.2.1. GIS 桌面 supermap-idesktopx-11.3.0-windows-x64-bin 下载链接&#xff1a;SuperMap技术资源中心|为您提供全面的在线技术服务 安装教程&#xff1a;绿色版&…

【西瓜书《机器学习》十至十二章内容通俗理解】

第十章&#xff1a;降维与度量学习 10.1 降维的概念 核心概念&#xff1a;降维就是把很多复杂的数据特征&#xff0c;用一些方法变成更少、更简单的特征&#xff0c;同时还尽量保留数据里重要的信息。这就好比你有一大箱各种各样的玩具&#xff0c;但是要搬到一个小房间里&am…

仿12306购票系统(3)

前面完成了乘车人登录功能的实现&#xff0c;本篇主要是控制台方面的管理 对于整体的控制台的设计&#xff0c;为了能够快速的检验&#xff0c;不进行登录拦截&#xff0c;在控制台的这个模块的controller层增加admin&#xff0c;以及在登录界面的拦截器排除掉admin. 车站 即…

【Java项目】基于Spring Boot的简历系统

【Java项目】基于Spring Boot的简历系统 技术简介&#xff1a;采用Spring Boot框架、Java技术、MySQL数据库等实现。 系统简介&#xff1a;系统主要实现了管理员模块、用户模块二大部分。管理员登录进入简历系统可以查看首页、个人中心、用户管理、简历模板管理、模板类型管理、…

基于YOLO11深度学习的苹果叶片病害检测识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…