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

news/2024/4/16 15:25:39/文章来源:https://blog.csdn.net/h8062651/article/details/136495783

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.luyixian.cn/news_show_996937.aspx

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

相关文章

Claude3、Gemini、Sora VS GPT-4:AI技术如何助力科研与产业发展?

【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚…

社区店选址评估:利用大数据选址的技巧与策略

在当今数字化的时代&#xff0c;利用大数据进行社区店选址评估已成为一种高效、科学的方法。作为一名开鲜奶吧5年的创业者&#xff0c;我将分享一些利用大数据选址的技巧与策略&#xff0c;帮助你找到最适合的店铺位置。 1、确定目标商圈 在选址之前&#xff0c;首先要明确自己…

C++初阶:初识C++

目录 1. 前言&#xff1a;C 与 C语言2. C对于C语言语法的完善与补充2.1 命名冲突与命名空间2.1.1 命名空间的定义2.1.2 调用方式 2.3 补充&#xff1a;流的概念2.4 缺省参数2.4.1 缺省参数的使用 2.5 函数重载2.5.1 什么是函数重载2.5.2 函数重载的使用2.5.3 特殊情况&#xff…

SpringBoot 热部署。

SpringBoot 热部署。 文章目录 SpringBoot 热部署。 pom.xml。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional…

Android 12.0 系统wifi列表显示已连接但无法访问网络问题解决

1.前言 在12.0的系统rom产品定制化开发中,在wifi模块也很重要,但是在某些情况下对于一些wifi连接成功后,确显示已连接成功,但是无法访问互联网 的情况,所以实际上这时可以正常上网的,就是显示的不正常,所以就需要分析连接流程然后解决问题 如图所示: 2.系统wifi列表显示…

IEEE 802.11 RTS/CTS/BA/Management

RTS/CTS IEEE 802.11 RTS/CTS即RTS/CTS协议(Request To Send/Clear To Send)即请求发送/清除发送协议是被802.11无线网络协议采用的一种用来减少由隐藏节点问题所造成的冲突的机制。 相当于一种握手协议,主要用来解决"隐藏终端"问题。"隐藏终端"(Hid…

HTML静态网页成品作业(HTML+CSS)——舞蹈网页设计制作(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码CSS部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 &#x1…

javaWebssh在线授课辅导系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh在线授课辅导系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7.…

用户角色的重要性:确保财务数据安全的最佳方式

在企业的财务管理业务中&#xff0c;一个人几乎不可能完成所有的财务记账任务&#xff0c;例如设定预算、发票审批等等&#xff0c;至少不能有效地执行。最为明智的方式&#xff0c;是将这些任务分派给特定的人员&#xff0c;比如部门经理、财务经理或者销售、市场人员等等。 但…

设计模式(二)单例模式

单例模式&#xff1a;确保一个类只有一个实例&#xff0c;并提供了全局访问点&#xff1b;主要是用于控制共享资源的访问&#xff1b; 单例模式的实现分为懒汉式和饿汉式。 懒汉式单例在需要时才会创建&#xff0c;而饿汉式单例则在类加载时立即创建实例&#xff1b; 单例模…

【airtest】自动化入门教程(二)airtest操作

目录 一、touch 二、wait 三、swipe 四、exists 五、text 六、keyevent 七、snapshot 八、sleep 九、断言 9.1 assert_exists 9.2 assert_not_exists 9.3 assert_equal 9.4 assert_not_equal 前言&#xff1a;本文主要针对aritest部分的基础操作,aritest是一个跨平…

Selenium上传文件有多少种方式?不信你有我全

Selenium 封装了现成的文件上传操作。但是随着现代前端框架的发展&#xff0c;文件上传的方式越来越多样。而有一些文件上传的控件&#xff0c;要做自动化控制会更复杂一些&#xff0c;这篇文章主要讨论在复杂情况下&#xff0c;如何通过自动化完成文件上传 1.input 元素上传文…

前端从普通登录到单点登录(SSO)

随着前端登录场景的日益复杂化和技术思想的不断演进&#xff0c;前端在登录方面的知识结构变得越来越复杂。对于前端开发者来说&#xff0c;在日常工作中根据不同的登录场景提供合适的解决方案是我们的职责所在&#xff0c;本文将梳理前端登录的演变过程。 1、无状态的HTTP H…

蜘蛛池是什么意思,怎么生成蜘蛛池

蜘蛛池是由自然界中的蜘蛛群落构成的一个小生态系统&#xff0c;也是身处自然界中的游客们可以在风雨中体验到最贴近自然气息的地方。 点开我主页面 Baidu蜘蛛的作用&#xff1a; 引蜘蛛逐渐收录&#xff0c;降权引蜘蛛可以疗伤&#xff0c;排名/收录不稳定&#xff0c;没有收…

Transformer中的FeedForward

Transformer中的FeedForward flyfish class PoswiseFeedForwardNet(nn.Module):def __init__(self, d_ff2048):super(PoswiseFeedForwardNet, self).__init__()# 定义一维卷积层 1&#xff0c;用于将输入映射到更高维度self.conv1 nn.Conv1d(in_channelsd_embedding, out_ch…

3.7作业

一 1&#xff09;应用层 负责处理不同应用程序之间的通信&#xff0c;需要满足提供的协议&#xff0c;确保数据发送方和接收方的正确 应用层提供的协议&#xff1a; &#xff08;2&#xff09;表示层 负责网络中通信的数据的编码和格式&#xff0c;确保通信过程中…

rust入门(1)创建项目

安装 vscode 安装插件 rust-analyzerNative Debug vscode 配置自动格式化代码 settings.json{"editor.defaultFoldingRangeProvider": null,"[rust]": {"editor.defaultFormatter": "rust-lang.rust-analyzer", // Makes the magi…

基于AFDPF主动频率偏移法的孤岛检测Simulink仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于AFDPF主动频率偏移法的孤岛检测Simulink仿真。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a 36 4.系统原理简介 在分布式发电系统中&#xff0c;孤…

【实战】K8S集群部署nacos并接入Springcloud项目容器化运维

文章目录 前言Nacos集群搭建Spring cloud配置nacos将Springcloud项目部署在k8s写在最后 前言 相信很多同学都开发过以微服务为架构的系统&#xff0c;开发微服务必不可少要使用注册中心&#xff0c;比如nacos\consul等等。当然在自动化运维流行的今天&#xff0c;我们也会将注…

windows部署ruoyi-vue-pro

前提 安装java 安装maven 安装redis mysql 源代码下载 后端 ruoyi-vue-pro 前端 yudao-ui-admin-vue3 后端项目 配置maven 导入数据 CREATE DATABASE ruoyi_vue_pro;修改mysql连接配置 修改redis 打包项目 mvn clean install package -Dmaven.test.skiptrue启动YudaoSe…