C++设计模式——抽象工厂模式

文章目录

    • 抽象工厂模式的主要组成部分
    • 抽象工厂模式的一个典型例子
    • 抽象工厂模式用于其他场景
    • 抽象工厂模式与其他设计模式结合使用

C++ 中的抽象工厂模式是一种创建型设计模式,它主要用于处理对象家族的创建,这些对象之间可能存在一定的关联关系或属于相同的产品族。抽象工厂模式的核心目标是提供一个接口,允许客户端通过此接口创建一系列相关或相互依赖的对象,而不必知道具体产生的对象的具体类。

抽象工厂模式的主要组成部分

  1. 抽象工厂(Abstract Factory):这是一个接口,声明了一组用于创建相关或依赖对象的方法,每个方法对应一种产品对象。

    class AbstractFactory {
    public:
      virtual ~AbstractFactory() {}
      virtual IProductA* createProductA() = 0; // 创建产品A的抽象方法
      virtual IProductB* createProductB() = 0; // 创建产品B的抽象方法
      // ... 可能还有其他产品方法
    };
    
  2. 具体工厂(Concrete Factory):这是抽象工厂接口的具体实现类,它负责创建一个产品族内的具体产品对象。

    class ConcreteFactory1 : public AbstractFactory {
    public:
      IProductA* createProductA() override { return new ConcreteProductA1(); }
      IProductB* createProductB() override { return new ConcreteProductB1(); }
    };
    
    class ConcreteFactory2 : public AbstractFactory {
    // ...
    };
    
  3. 产品接口(Product Interface):代表产品对象的抽象接口,定义了产品的公共方法。

    class IProductA {
    public:
      virtual ~IProductA() {}
      // 声明产品A的相关操作
    };
    
    class IProductB {
    public:
      virtual ~IProductB() {}
      // 声明产品B的相关操作
    };
    
  4. 具体产品(Concrete Product):实现了产品接口的具体产品类。

    class ConcreteProductA1 : public IProductA {
    // 实现产品A1的具体行为
    };
    
    class ConcreteProductB1 : public IProductB {
    // 实现产品B1的具体行为
    };
    
    // 同样会有 ConcreteProductA2, ConcreteProductB2 等...
    

使用抽象工厂模式的优势在于:

  • 隔离了具体的产品实现:客户端只需关心抽象工厂的接口,无需了解创建对象的具体细节。
  • 方便产品族的整体替换:如果想切换到同一产品族的不同实现,只需更改使用的具体工厂即可。
  • 确保产品一致性:通过抽象工厂创建的对象遵循一套一致的设计规则,适合那些必须一起工作的对象集合。

然而,抽象工厂模式也有其局限性,例如难以添加新的产品种类,因为它要求修改抽象工厂接口以及相应的具体工厂实现。此外,随着产品数量的增加,系统的复杂性也会提高。

抽象工厂模式的一个典型例子

在实际应用中,抽象工厂模式的一个典型例子是操作系统 GUI 库的创建。比如,我们有一个抽象工厂来创建按钮、文本框等各种 GUI 组件,而每个具体工厂(如 WindowsFactory 或 LinuxFactory)则负责创建相应操作系统下的具体 GUI 组件。

// 抽象工厂接口
class GUIFactory {
public:
    virtual ~GUIFactory() {}
    virtual Button* createButton() const = 0;
    virtual TextBox* createTextBox() const = 0;
    // 其他组件的创建方法...
};

// 具体工厂
class WindowsFactory : public GUIFactory {
public:
    Button* createButton() const override { return new WindowsButton(); }
    TextBox* createTextBox() const override { return new WindowsTextBox(); }
    // ...
};

class LinuxFactory : public GUIFactory {
public:
    Button* createButton() const override { return new LinuxButton(); }
    TextBox* createTextBox() const override { return new LinuxTextBox(); }
    // ...
};

// 产品接口
class Button {
public:
    virtual ~Button() {}
    virtual void draw() const = 0;
    // ...
};

class TextBox {
public:
    virtual ~TextBox() {}
    virtual void draw() const = 0;
    // ...
};

// 具体产品
class WindowsButton : public Button {
public:
    void draw() const override { /*绘制Windows风格的按钮*/ }
    // ...
};

class WindowsTextBox : public TextBox {
public:
    void draw() const override { /*绘制Windows风格的文本框*/ }
    // ...
};

// Linux下对应的Button和TextBox实现...

在客户端代码中,我们可以根据需要选择合适的工厂来创建一整套风格一致的界面组件:

int main() {
    GUIFactory* factory;
    if (isWindowsPlatform()) {
        factory = new WindowsFactory();
    } else if (isLinuxPlatform()) {
        factory = new LinuxFactory();
    }

    Button* myButton = factory->createButton();
    TextBox* myTextBox = factory->createTextBox();

    // 使用创建出来的组件
    myButton->draw();
    myTextBox->draw();

    delete myButton;
    delete myTextBox;
    delete factory;

    return 0;
}

这样,无论操作系统环境如何变化,客户端代码都可以保持不变,体现了开闭原则——对扩展开放,对修改关闭。同时,由同一家工厂创建出来的组件具有内在的一致性,可以很好地协同工作。

抽象工厂模式用于其他场景

此外,抽象工厂模式还常用于其他场景,例如:

  • 数据库访问:抽象工厂可以定义创建不同数据库连接、执行SQL命令等操作的方法,而具体工厂可以是MySQLFactory、OracleFactory等,分别用来创建各自数据库系统的连接对象和查询命令对象。
// 抽象工厂
class DatabaseFactory {
public:
    virtual ~DatabaseFactory() {}
    virtual Connection* createConnection() const = 0;
    virtual Query* createQuery() const = 0;
};

// 具体工厂
class MySQLFactory : public DatabaseFactory {
public:
    Connection* createConnection() const override { return new MySQLConnection(); }
    Query* createQuery() const override { return new MySQLQuery(); }
};

class OracleFactory : public DatabaseFactory {
public:
    Connection* createConnection() const override { return new OracleConnection(); }
    Query* createQuery() const override { return new OracleQuery(); }
};

// 产品接口
class Connection {
public:
    virtual ~Connection() {}
    virtual bool connect(const std::string& host, int port, const std::string& user, const std::string& password) = 0;
    // 其他连接相关方法...
};

class Query {
public:
    virtual ~Query() {}
    virtual ResultSet* execute(const std::string& sql) = 0;
    // 其他查询相关方法...
};

// 具体产品类...

通过这种设计模式,软件架构得以解耦,使得各个部分能够独立变化和发展,同时确保了系统内部组件间的兼容性和一致性。在复杂的应用场景中,抽象工厂模式尤其有助于模块化设计和维护。

抽象工厂模式与其他设计模式结合使用

在更高级别的软件体系结构设计中,抽象工厂模式还可以与其他设计模式结合使用,以构建更为灵活和可扩展的解决方案。例如:

  • 与策略模式结合:抽象工厂可以返回一组实现了某种策略接口的对象,这样客户可以根据需求选择不同的策略组合。例如,在图形渲染引擎中,抽象工厂可以创建不同的渲染策略(如光照策略、纹理策略),然后将它们组合起来形成特定的效果。

  • 与工厂方法模式结合:抽象工厂中的某些方法可以进一步采用工厂方法模式,即在具体工厂内定义创建单个产品的工厂方法,使得产品创建逻辑更加灵活且易于扩展。

  • 与装饰器模式配合:当产品家族中存在需要逐步增强或修改的组件时,可以在获取基础组件后,通过装饰器模式为其添加额外的功能或属性。

  • 与服务定位器模式搭配:在大型系统中,抽象工厂可以与服务定位器模式相结合,通过服务定位器查找并注入所需的抽象工厂实例,以便在运行时决定具体使用哪种工厂。

总的来说,抽象工厂模式是一个强大而实用的设计模式,它不仅帮助我们组织和管理相关联的产品族,而且在很大程度上增强了代码的可复用性和可扩展性。但在实际应用时需要注意权衡其带来的灵活性与增加的复杂性,尤其是在产品家族变动频繁或者产品种类较少的情况下,直接使用简单工厂或工厂方法模式可能更为合适。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

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

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

相关文章

Vue页面更新后刷新页面不会渲染解决

小编今天犯了个很低级的错误,导致VUE页面刷新样式不会更新的问题! 解决方法:查看你的路由路径大小写是否正确!小编是犯了这种错误,特此分享下!

HarmonyOS—端云一体化组件

概述 DevEco Studio还为您提供多种端云一体化组件。集成端云一体化组件后,您只需进行简单配置即可向应用用户提供登录、支付等众多功能。 登录组件 您可使用端云一体化登录组件向应用用户提供登录和登出功能,目前支持帐号密码登录、手机验证码登录、以…

k8s部署 多master节点负载均衡以及集群高可用

一、k8s 添加多master节点实验 1、master02节点初始化操作 2、在master01节点基础上,完成master02节点部署 ①从master01节点复制所需要的文件 需要从master01节点复制etcd数据库所需要的ssl证书、kubernetes安装目录(二进制文件、组件与apiserver通信…

单调栈-算法题

739. 每日温度 题目 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。 示…

select * from 表 c=‘1‘ and b=‘2‘ and a=‘3‘; abc是联合索引,这样查询会命中索引吗?

倒叙也会命中索引 但是要注意,倒叙的时候必须要有a存在,否则就会索引失效 因为mysql底层会有优化器去进行优化,但是如果没有a的话,那么优化器就不知道要优化那个索引了,所以他走了全表,导致索引失效

深入理解Linux线程(LWP):概念、结构与实现机制(1)

🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:会いたい—Naomile 1:12━━━━━━️💟──────── 4:59 🔄 ◀️ ⏸ ▶️ ☰ &a…

【rust】10 project、crate、mod、pub、use、项目目录层级组织、概念和实战

文章目录 一、项目目录层级组织概念1.1 cargo new 创建同名 的 Project 和 crate1.2 多 crate 的 package1.3 mod 模块1.3.1 创建嵌套 mod1.3.2 mod 树1.3.3 用路径引用 mod1.3.3.1 使用绝对还是相对? 1.3.4 代码可见性1.3.4.1 pub 关键字1.3.4.2 用 super 引用 mod1.3.4.3 用…

内衣洗衣机什么牌子好又便宜?实力非凡机型深度测评

内衣裤这种小件的衣物紧密接触皮肤,更是接触特殊生理部位,所以,内衣裤对卫生标准有着特殊要求,现在很多人都是,把内衣裤放到家里的大型洗衣机和其他衣物混洗,你应该知道大型洗衣机由于长期清洗一些大件的衣…

1.2 debug的六种指令的使用,四个通用寄存器

汇编语言 首先进入环境 mount c d:masm //把c挂载在d盘中的masm当中 c: //进入c,进入到编译环境 dir //查看文件,可有可无Debug是DOS、Windows都提供的实模式(8086 方式)程序的调试工具。使用它可以查看CPU各种寄存器中的内容…

Find My运动相机|苹果Find My技术与相机结合,智能防丢,全球定位

运动相机设计用于在各种运动和极限环境中使用,如徒步、登山、攀岩、骑行、滑翔、滑雪、游泳和潜水等,它们通常具有防抖防震、深度防水和高清画质的特点,能够适应颠簸剧烈的环境,甚至可以承受一定程度的摔落,一些运动相…

Go开发 入门以VSCode为例

一、Go环境搭建 1.1 安装 进入Golang官网 https://go.dev,点击 Download 若无法打开网页可以使用国内的Go语言中文网 https://studygolang.com/dl 进入下载 找到合适的平台点击链接下载即可(这里以Windows距离) 下载完成后 Next Next 安…

rabbitmq重编辑版本

消息队列RabbitMQ详细使用 文章目录 消息队列RabbitMQ详细使用MQ 的相关概念什么是MQ为什么要用MQMQ 的分类MQ 的选择 RabbitMQRabbitMQ 的概念四大核心概念各个名词介绍安装RabbitMQWeb管理界面及授权操作Docker 安装Hello world简单示例 Work Queues轮训分发消息消息应答自动…

【数据分享】2001-2022年我国省市县镇四级的逐日平均降水量数据(免费获取\excel\shp格式)

降水数据是我们在各项研究中最常用的气象指标之一!之前我们给大家分享过来源于国家青藏高原科学数据中心发布的1961—2022年全国范围的逐日降水栅格数据(可查看之前的文章获悉详情)! 本次我们分享的是2001-2002年我国省市县镇四个…

基础!!!吴恩达deeplearning.ai:卷积层

以下内容有任何不理解可以翻看我之前的博客哦:吴恩达deeplearning.ai专栏 文章目录 回顾——密集层 Dense Layer卷积层 Convolutional Neural Network定义优势具体说明心电图卷积层搭建 到目前为止,你使用的所有神经网络层都是密集层类型,这…

瑞_23种设计模式_组合模式

文章目录 1 组合模式(Composite Pattern)1.1 介绍1.2 概述1.3 组合模式的结构1.4 组合模式的分类1.5 组合模式的优点1.6 组合模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 🙊 前言:本文章为瑞_系列…

AI大模型-启航

文章目录 什么是大模型?(大体现在参数量巨大)大模型将会改变那些行业(大模型有哪些作用?)如何搞数据训练模型?LangChain带来的技术变革LangChain架构 什么是大模型?(大体…

网络编程作业day2

1.将TPC和UDP通信模型各敲两遍 &#xff08;1&#xff09;TPC通信模型&#xff1a; 服务器代码&#xff1a; #include <myhead.h> #define SERVER_IP "192.168.125.136" #define SERVER_PORT 1314 int main(int argc, const char *argv[]) {//1、创建用于监…

信号系统之滤波器比较

比较 1&#xff1a;模拟与数字滤波器 大多数数字信号源自模拟电子设备。**如果需要对信号进行滤波&#xff0c;是在数字化之前使用模拟滤波器&#xff0c;还是在数字化后使用数字滤波器更好&#xff1f;**将通过两个对比来回答问题。 目标是提供 1 kHz的低通滤波器。模拟端是…

八股文打卡day24——数据库(1)

面试题&#xff1a;左连接和右连接的区别&#xff1f; 我的回答&#xff1a; 左连接的SQL语句是&#xff1a;左表 left join 右表 on 连接条件&#xff0c;表示以左表为基础&#xff0c;将左表的的所有记录与右表进行连接。即使右表中没有与左表匹配的记录&#xff0c;左连接…

ROS 2基础概念#2:节点(Node)| ROS 2学习笔记

ROS 2节点简介 节点是执行计算的进程。节点组合在一起形成一个图&#xff08;graph&#xff09;&#xff0c;并使用主题&#xff08;topic&#xff09;、服务&#xff08;service&#xff09;和参数服务器&#xff08;paramter server&#xff09;相互通信。这些节点旨在以细粒…