突破编程_C++_设计模式(装饰器模式)

1 装饰器模式的基本概念

在 C++ 中,装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活,它可以在不修改现有类结构的情况下增加新的功能。

装饰器模式的基本概念包括:

(1)组件(Component): 这是一个接口或抽象类,定义了对象的核心功能。装饰器模式和组件一起工作,允许组件被装饰。

(2)具体组件(Concrete Component): 实现了组件接口或抽象类的具体类。它是被装饰的对象。

(3)装饰器(Decorator): 这是一个接口或抽象类,继承自组件接口,并持有一个组件对象的引用。装饰器允许在运行时向组件添加职责。

(4)具体装饰器(Concrete Decorator): 实现了装饰器接口或抽象类的具体类。它给组件添加额外的功能。

在 C++ 中,装饰器模式通常通过继承和接口实现。具体装饰器类会继承装饰器基类,并在其方法中实现对组件的调用以及额外的功能。装饰器对象会持有一个组件对象的引用,并在其方法中将其传递给其他装饰器或具体组件。

2 装饰器模式的实现步骤

在C++中实现装饰器模式通常涉及以下步骤:

(1)定义组件接口:
首先,定义一个接口或抽象基类,它声明了将被装饰对象应有的核心功能。这个接口是装饰器模式中的关键部分,因为它允许装饰器和组件对象以统一的方式工作。

(2)实现具体组件:
接下来,创建实现了组件接口的具体类。这些类通常包含实际要执行的操作。

(3)创建装饰器接口:
装饰器接口或抽象基类继承自组件接口。它持有一个指向组件对象的引用,并且通常会提供一个构造函数,允许在创建装饰器对象时传入一个组件对象。

(4)实现具体装饰器:
具体装饰器类实现了装饰器接口,并且可以在其操作中添加额外的功能,同时调用组件对象上的操作。通过这种方式,装饰器可以在运行时动态地增强组件的功能。

(5)使用装饰器:
最后,客户端代码创建组件对象,并使用装饰器来增强它们的功能。这可以通过简单地创建装饰器对象并将组件对象作为参数传递来实现。装饰器可以嵌套使用,从而允许添加多个额外的功能。

下面是一个简单的装饰器模式实现示例:

#include <iostream>  
#include <memory>  // 步骤 1: 定义组件接口  
class Component {
public:virtual void operation() = 0;virtual ~Component() = default;
};// 步骤 2: 实现具体组件  
class ConcreteComponent : public Component {
public:void operation() override {std::cout << "ConcreteComponent operation" << std::endl;}
};// 步骤 3: 创建装饰器接口  
class Decorator : public Component {
public:explicit Decorator(std::unique_ptr<Component> comp) : component(std::move(comp)) {}void operation() override {if (component != nullptr) {component->operation();}}protected:std::unique_ptr<Component> component;
};// 步骤 4: 实现具体装饰器  
class ConcreteDecoratorA : public Decorator {
public:explicit ConcreteDecoratorA(std::unique_ptr<Component> comp) : Decorator(std::move(comp)) {}void operation() override {std::cout << "ConcreteDecoratorA operation" << std::endl;Decorator::operation();}
};class ConcreteDecoratorB : public Decorator {
public:explicit ConcreteDecoratorB(std::unique_ptr<Component> comp) : Decorator(std::move(comp)) {}void operation() override {Decorator::operation();std::cout << "ConcreteDecoratorB operation" << std::endl;}
};// 步骤 5: 使用装饰器  
int main() 
{// 创建组件对象并使用智能指针管理  std::unique_ptr<Component> component = std::make_unique<ConcreteComponent>();// 使用装饰器增强组件,并传递智能指针  component = std::make_unique<ConcreteDecoratorA>(std::move(component));component = std::make_unique<ConcreteDecoratorB>(std::move(component));// 执行操作  component->operation();// 智能指针会自动管理内存,无需手动删除  return 0;
}

上面代码的输出为:

ConcreteDecoratorA operation
ConcreteComponent operation
ConcreteDecoratorB operation

在这个示例中,Component 是组件接口,ConcreteComponent 是具体组件,Decorator 是装饰器接口,ConcreteDecoratorA 和 ConcreteDecoratorB 是具体装饰器。在 main 函数中,创建了一个组件对象,并使用两个装饰器来增强它。最终,当调用 operation 方法时,会依次执行两个装饰器添加的额外功能和组件自身的操作。

3 装饰器模式的应用场景

C++ 装饰器模式的应用场景主要涉及以下几个方面:

(1)扩展功能而不修改源代码: 当你想要给一个已存在的类添加新功能,但又不想修改其源代码时,装饰器模式非常有用。通过创建装饰器类来包装原始类,你可以在不改变原始类结构的情况下添加新功能。

(2)动态行为组合: 你可以使用不同的装饰器来动态地组合对象的行为。例如,一个对象可以在不同时间点上被不同的装饰器装饰,从而实现不同的功能组合。

(3)遵循开闭原则: 装饰器模式遵循开闭原则,意味着软件实体(类、模块、函数等)应当是可扩展,而不可修改的。通过使用装饰器,你可以在不修改现有代码的情况下扩展系统的功能。

(4)实现灵活的功能扩展: 与继承相比,装饰器模式提供了更加灵活的功能扩展机制。通过继承实现的功能扩展是静态的,而装饰器模式允许动态地添加或移除功能。

(5)多层次的功能组合: 装饰器模式支持多层次的功能组合。你可以通过嵌套使用多个装饰器来组合多个功能,实现复杂的功能组合。

(6)处理具有多种可选行为的对象: 如果一个对象有多种可选行为,并且这些行为可以动态地改变,那么装饰器模式是一个很好的选择。例如,一个文本编辑器可能有多种可选的字体、颜色、大小等设置,这些设置可以动态地改变编辑器的外观和行为。

在实际应用中,装饰器模式常用于实现如I/O流、网络协议、GUI框架、数据库查询优化等场景,其中需要动态地组合和扩展功能。通过使用装饰器模式,你可以提高代码的灵活性和可维护性,同时保持代码的清晰和易于理解。

3.1 装饰器模式在动态行为组合的典型应用

C++ 装饰器模式在动态行为组合的典型应用之一是创建一个组件(如服务、接口或策略)的多个实现,并在运行时根据需求动态地组合这些实现。下面是一个简单的示例,展示了如何使用装饰器模式来动态组合不同的行为。

首先,定义一个接口,它代表可以被装饰的对象:

#include <iostream>  
#include <memory>  // 步骤 1: 定义组件接口  
class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};

接下来,实现一个具体的组件类,该类继承自组件接口,并实现了接口中定义的行为。

// 步骤 2: 实现具体组件  
class Circle : public Shape {
public:void draw() override {std::cout << "Drawing a circle..." << std::endl;}
};

然后,创建一个装饰器接口,它同样继承自组件接口,并包含一个指向组件对象的成员变量。

// 步骤 3: 创建装饰器接口  
class ShapeDecorator : public Shape {
public:explicit ShapeDecorator(std::unique_ptr<Shape> shape) : decoratedShape(std::move(shape)) {}void draw() override {decoratedShape->draw();}protected:std::unique_ptr<Shape> decoratedShape;
};

现在,实现具体的装饰器类,它们继承自装饰器接口,并添加新的行为。

// 步骤 4: 实现具体装饰器  
class RedShapeDecorator : public ShapeDecorator {
public:explicit RedShapeDecorator(std::unique_ptr<Shape> shape) : ShapeDecorator(std::move(shape)) {}void draw() override {setRedColor();ShapeDecorator::draw();}private:void setRedColor() {std::cout << "Setting color to red..." << std::endl;}
};class BoldShapeDecorator : public ShapeDecorator {
public:explicit BoldShapeDecorator(std::unique_ptr<Shape> shape) : ShapeDecorator(std::move(shape)) {}void draw() override {setBoldStyle();ShapeDecorator::draw();}private:void setBoldStyle() {std::cout << "Setting style to bold..." << std::endl;}
};

最后,在主函数中,创建组件对象并使用装饰器来增强它的功能。

// 步骤 5: 使用装饰器  
int main() {// 创建组件对象并使用智能指针管理  std::unique_ptr<Shape> shape = std::make_unique<Circle>();// 使用装饰器增强组件  shape = std::make_unique<RedShapeDecorator>(std::move(shape));shape = std::make_unique<BoldShapeDecorator>(std::move(shape));// 执行操作  shape->draw();// 智能指针会自动管理内存,无需手动删除  return 0;
}

上面这些代码的输出为:

Setting style to bold...
Setting color to red...
Drawing a circle...

在这个示例中,Shape 是一个组件接口,Circle 是一个实现了 Shape 接口的具体组件。ShapeDecorator 是一个装饰器接口,它持有一个 Shape 对象的智能指针,并允许在调用 draw 方法时修改行为。RedShapeDecorator 和 BoldShapeDecorator 是具体的装饰器实现,它们分别添加了设置颜色和设置样式的行为。

在 main 函数中,首先创建了一个 Circle 对象,并使用 std::unique_ptr 来管理它。然后通过创建 RedShapeDecorator 和 BoldShapeDecorator 对象来动态地给 Circle 对象添加颜色和样式。最后,当调用 shape->draw() 时,会按照添加装饰器的顺序执行所有的行为。

这个示例展示了如何使用装饰器模式来动态地组合多个行为。通过组合不同的装饰器,可以很容易地改变对象的行为,而不需要修改原始组件的代码。这种灵活性使得装饰器模式在需要动态行为组合的场景中非常有用。

3.2 装饰器模式在数据库查询优化场景中的典型应用

在数据库查询优化的场景中,装饰器模式可以用来动态地改变或增强查询的行为,比如添加缓存、日志记录、性能统计等。

下面是一个简化的示例,展示了如何使用装饰器模式来优化数据库查询。在这个例子中,我们假设有一个DatabaseQuery接口,以及一个实现了该接口的SelectQuery类。我们还创建了一个QueryDecorator基类,它接受一个DatabaseQuery对象,并可以添加额外的优化逻辑。

首先,定义DatabaseQuery接口:

class DatabaseQuery {
public:virtual ~DatabaseQuery() = default;virtual void execute() = 0; // 执行查询  
};

然后,实现SelectQuery类,它继承自DatabaseQuery:

class SelectQuery : public DatabaseQuery {
public:void execute() override {// 执行实际的数据库查询  std::cout << "Executing select query..." << std::endl;}
};

接下来,创建QueryDecorator基类,它同样继承自DatabaseQuery,并接受一个指向DatabaseQuery的指针:

class QueryDecorator : public DatabaseQuery {
public:explicit QueryDecorator(std::unique_ptr<DatabaseQuery> query) : decoratedQuery(std::move(query)) {}void execute() override {// 在执行查询之前或之后添加额外的逻辑  decoratedQuery->execute();}protected:std::unique_ptr<DatabaseQuery> decoratedQuery;
};

现在,可以创建具体的装饰器类来优化查询。例如,创建一个CachingQueryDecorator,它在执行查询之前检查缓存:

class CachingQueryDecorator : public QueryDecorator {
public:explicit CachingQueryDecorator(std::unique_ptr<DatabaseQuery> query) : QueryDecorator(std::move(query)) {}void execute() override {// 检查缓存  if (isCached()) {std::cout << "Query is cached, retrieving from cache..." << std::endl;// 从缓存中获取数据  return;}// 如果缓存中没有,则执行原始查询  std::cout << "Query is not cached, executing original query..." << std::endl;QueryDecorator::execute();// 假设这里会将查询结果存入缓存  }private:bool isCached() {// 实现缓存检查逻辑  // 返回true表示缓存中有数据,返回false表示没有  return false; // 示例中总是返回false  }
};

最后,在 main 函数中,可以使用这些类来执行查询,并利用装饰器来优化它::

int main() 
{// 创建原始查询  std::unique_ptr<DatabaseQuery> query = std::make_unique<SelectQuery>();// 使用装饰器来优化查询  query = std::make_unique<CachingQueryDecorator>(std::move(query));// 执行查询  query->execute();return 0;
}

上面这些代码的输出为:

Query is not cached, executing original query...
Executing select query...

在这个示例中,CachingQueryDecorator 装饰器在执行原始查询之前检查了缓存。如果数据在缓存中,它就从缓存中检索数据,否则它执行原始查询。这只是一个简单的例子,实际的数据库查询优化可能会涉及更复杂的逻辑,比如查询重写、索引使用、并行执行等。

4 装饰器模式的优点与缺点

C++ 装饰器模式的优点主要包括:

(1)动态增加功能: 装饰器模式允许在运行时动态地给对象添加新的功能,这使得程序具有更大的灵活性和可扩展性。可以根据需要添加或删除装饰器,而无需修改原始类的代码。

(2)遵循开闭原则: 使用装饰器模式,可以在不修改原始类的情况下扩展其功能,这符合开闭原则,即“软件实体(类、模块、函数等等)应当是可扩展,而不可修改的”。

(3)减少耦合: 装饰器和被装饰的对象可以独立发展,它们之间的耦合度很低。这意味着可以独立地改变装饰器或原始类的实现,而不会影响到另一方。

(4)提供多种组合方式: 通过组合不同的装饰器,可以实现不同的功能组合,从而满足不同的需求。

然而,C++ 装饰器模式也存在一些缺点:

(1)增加系统复杂性: 使用装饰器模式可能会增加系统的复杂性,因为需要创建大量的装饰器类来实现不同的功能。这可能会导致代码难以理解和维护。

(2)性能开销: 由于装饰器模式涉及到对象的嵌套和链式调用,可能会带来一定的性能开销。在每次调用方法时,都需要遍历装饰器链,这可能会降低程序的执行效率。

(3)调试困难: 当使用多层装饰器时,调试可能会变得困难。因为错误可能发生在原始对象、装饰器或它们之间的交互中,需要仔细检查每个部分的代码来确定问题的根源。

因此,在使用装饰器模式时,需要权衡其优点和缺点,根据具体的项目需求来决定是否使用该模式。在某些情况下,可能更适合使用继承或其他设计模式来实现类似的功能。

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

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

相关文章

一 超级数据查看器 讲解稿 系统介绍

一 超级数据查看器 讲解稿 系统介绍 APP下载地址 百度手机助手 下载地址4 点此此处 以新页面方式 打开B站 教学视频 讲解稿 大家好&#xff0c;这里我给大家介绍一下超级数据查看器&#xff0c; 超级数据查看器。就是桌面这个蓝色的房子图形的APP。 超级数据查看器是一个提供数…

HTML 学习笔记 总结

总结 【标签按照功能进行分类】&#xff1a; <!DOCTYPE html>&#xff1a;声明为 HTML5 文档 <html>&#xff08;双标记、块标记&#xff09;&#xff1a;是 HTML 页面的根元素&#xff0c;定义 HTML 文档 <head>&#xff08;双标记、块标记&#xff09;&a…

算法-双指针、BFS与图论-1224. 交换瓶子

题目 思路 可以交换任意两个瓶子&#xff0c;最多n-1次&#xff1b;如果是只能交换相邻的瓶子&#xff0c;那么相当于逆序对的个数&#xff08;这篇博客是介绍如何计算逆序对的算法&#xff1a;算法篇&#xff1a;逆序对_逆序对算法-CSDN博客&#xff09;本题转换为图论去看:边…

【数据结构与算法】绪论

目录 一、数据结构研究 二、基本概念和术语 2.1 基本概念 2.2 什么是数据结构&#xff1f; 2.3 数据结构内容 2.4 逻辑结构种类 2.5 存储结构种类 2.6 数据类型和抽象数据类型 三、算法和算法分析 3.1 算法的定义 3.2 算法的特性 3.3 算法设计要求 3.4 算法好坏评…

JAVA虚拟机实战篇之GC调优[1](GC调优基知、方法、工具和常见GC模式)

文章目录 版权声明GC调优概念GC调优核心指标(KPI)吞吐量延迟&#xff08;Latency&#xff09;内存使用量 GC调优方法GC调优步骤GC调优工具jstat工具visualvm插件Prometheus Grafana GC日志分析GC日志保存GC日志分析工具GC ViewerGCeasy 常见的GC模式正常情况缓存对象过多情况内…

01_electron入门

由于毕业论文可能需要用 electron&#xff0c;所以 Linux 驱动学习慢了下来。 一、安装 node.js 进入 node.js 官网&#xff1a;Node.js (nodejs.org) 咱们就是用稳定版&#xff0c;安装包除了安装路径自己选择外&#xff0c;一直点 Next。 安装完成后需要配置环境&#xff0c…

如有Kata

养成跑步的习惯&#xff0c;就能习惯性跑步&#xff0c;一有空就见缝插针抽空跑步。这是一层韵律感、完成感、美感、成就感。而一次跑步的一连串动作&#xff0c;是另一层韵律感、完成感、美感、成就感。所以这里就有了两层的韵律感、完成感、美感、成就感。如是如水漂荡漾。健…

【机器学习】一文掌握逻辑回归全部核心点(下)。

逻辑回归核心点-下 1、引言2、逻辑回归核心点2.5 特征工程2.5.1 特征缩放2.5.2 多项式特征 2.6 多分类2.6.1 一对多&#xff08;One-vs-Rest&#xff0c;OvR&#xff09;策略2.6.2 一对一&#xff08;One-vs-One&#xff0c;OvO&#xff09;策略2.6.2 比较 2.7 评估指标2.7.1 准…

动手做一个最小RAG——TinyRAG

Datawhale干货 作者&#xff1a;宋志学&#xff0c;Datawhale成员 大家好&#xff0c;我是不要葱姜蒜。 接下来我会带领大家一步一步地实现一个简单的RAG模型&#xff0c;这个模型是基于RAG的一个简化版本&#xff0c;我们称之为Tiny-RAG。Tiny-RAG是一个基于RAG的简化版本&am…

SpringBoot源码

SpringBoot核心前置内容 1.Spring注解编程的发展过程 1.1 Spring 1.x 2004年3月24日&#xff0c;Spring1.0 正式发布&#xff0c;提供了IoC&#xff0c;AOP及XML配置的方式。 在Spring1.x版本中提供的是纯XML配置的方式&#xff0c;也就是在该版本中必须要提供xml的配置文件…

八、词嵌入语言模型(Word Embedding)

词嵌入&#xff08;Word Embedding, WE&#xff09;&#xff0c;任务是把不可计算、非结构化的词转换为可以计算、结构化的向量&#xff0c;从而便于进行数学处理。 一个更官方一点的定义是&#xff1a;词嵌入是是指把一个维数为所有词的数量的高维空间&#xff08;one-hot形式…

小迪安全36WEB 攻防-通用漏洞XSS 跨站MXSSUXSSFlashXSSPDFXSS

#XSS跨站系列内容:1. XSS跨站-原理&分类&手法 XSS跨站-探针&利用&审计XSS跨站另类攻击手法利用 XSS跨站-防御修复&绕过策略 #知识点&#xff1a; 1、XSS 跨站-原理&攻击&分类等 2、XSS 跨站-MXSS&UXSS&FlashXss&PDFXSS 等 1、原…

HCS-华为云Stack-计算节点内部网络结构

HCS-华为云Stack-计算节点内部网络结构 图中表示的仅为计算节点是两网口的模式&#xff0c;如果是四网口模式&#xff0c;系统会再自动创建一个网桥出来 图中未画出存储平面和Internal Base平面&#xff0c;它们和tunnel bearing、External OM-样&#xff0c;都是通过trunk0的…

信息系统项目管理师006:车联网(1信息化发展—1.2现代化基础设施—1.2.3车联网)

文章目录 1.2.3 车联网1.体系框架2.链接方式3.场景应用 记忆要点总结 1.2.3 车联网 车联网是新一代网络通信技术与汽车、电子、道路交通运输等领域深度融合的新兴产业形态。智能网联汽车是搭载先进的车载传感器、控制器、执行器等装置&#xff0c;并融合现代通信与网络技术&…

Linux常用命令之top监测

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ &#x1f440;&#x1f440;&#x1f440; 个人博客&#xff1a;小奥的博客 &#x1f44d;&#x1f44d;&#x1f44d;&#xff1a;个人CSDN ⭐️⭐️⭐️&#xff1a;传送门 &#x1f379; 本人24应届生一枚&#xff0c;技术和水平有限&am…

for、while、do While、for in、forEach、map、reduce、every、some、filter的使用

for、while、do While、for in、forEach、map、reduce、every、some、filter的使用 for let arr [2, 4, 6, 56, 7, 88];//for for (let i 0; i < arr.length; i) {console.log(i : arr[i]) //0:2 1:4 2:6 3:56 4:7 5:88 }普通的for循环可以用数组的索引来访问或者修改…

代码随想录day32 Java版

62.不同路径 public static int uniquePaths(int m, int n) {int[][] dp new int[m][n];//初始化for (int i 0; i < m; i) {dp[i][0] 1;}for (int i 0; i < n; i) {dp[0][i] 1;}for (int i 1; i < m; i) {for (int j 1; j < n; j) {dp[i][j] dp[i-1][j]dp…

Java享元模式源码剖析及使用场景

享元模式 一、介绍二、基本原理三、企业资源管理系统中使用案例三、Java 中的字符串常量池使用了享元模式四、总结优缺点以及使用经验 一、介绍 享元模式是一种结构型设计模式&#xff0c;旨在最大程度地减少内存使用或计算开销。这种模式通过共享对多个类似对象实例所需的状态…

04 数据结构之队列

循环队列 /* squence_queue.h */ #ifndef _SQUENCE_QUEUE_H_ #define _SQUENCE_QUEUE_H_#include <stdio.h> #include <string.h> #include <stdlib.h>#define QUEUE_SIZE 128 #define DEBUG(msg) \printf("--%s--, %s", __func__, msg)typedef i…

SAP BTP Hyperscaler PostgreSQL都有哪些Performance监控 (一)

前言 SAP BTP云平台中&#xff0c;除了自身的HANA数据库作为首选以外&#xff0c;它还支持PostgreSQL的整套服务&#xff0c;并以PaaS的形式提供给客户。你可以按照实例为单位进行购买申请不同标准规格的PG实例&#xff0c;然后构建自己的业务逻辑。Hyperscaler是这套产品或方…