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

news2025/4/22 20:16:15

文章目录

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

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)
————————————————

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

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

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

相关文章

springboot227旅游管理系统

springboot旅游管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本旅游管理系统就是在这样的大环境下诞生,其可以帮助使用者在…

C++ deque详解以及容器适配器

目录 1.容器适配器 2.deque的使用 2.1deque的介绍 2.2deque的缺陷 2.3deque作为stack和queue的可行性 2.4 deque类的使用 2.4.1deque的构造函数 2.4.2deque容量操作 2.4.3deque赋值,插入 1.容器适配器 适配器是一种设计模式(设计模式是一套被人…

STL常见容器(stack、queue容器)---C++

STL常见容器目录: 4.stack容器4.1 stack 基本概念4.2 stack 常用接口 5.queue容器5.1 queue常用接口5.2 queue常用接口 4.stack容器 4.1 stack 基本概念 概念: stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口. 注意…

重推请求之curl和fiddler

在实际的项目中会有出现问题,想重现的场景,比较重新调用一个服务,那么如何进行快速的重推请求呢,记录下来,方便备查。 主要有curl和fiddler两种方式,下面详细说。 方式一、curl 命令 curl 是一个利用URL规…

MySQL:索引有哪些(清晰明了)

一提到索引,可能就会想到B树索引、Hash索引、聚簇索引、主键索引、唯一索引、联合索引等等,但这些名词并不能混为一谈,他们有重复的部分,是从不同方面给索引取的名字。 从数据结构上来讲:B树索引、Hash索引、Full-text…

Spring注解之处理常见的 HTTP 请求

5 种常见的请求类型: GET :请求从服务器获取特定资源。举个例子:GET /users(获取所有学生)POST :在服务器上创建一个新的资源。举个例子:POST /users(创建学生)PUT :更新…

总结成果,擘画蓝图 | 易我科技召开2023年度总结暨2024年规划大会

2024年2月1日下午,易我科技举行了2023年度总结暨2024年规划大会。 01 首先,易我科技总经理万建华对2023年度整体工作进行了总结,对取得的经营成果给予了充分肯定。 ▲ 万总公布2023年经营成果 在肯定成绩的同时,也必须正视存在…

Leetcode : 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 思路:遍历数组元素,判定为0,则采用erase从数组删除&…

P沟道与N沟道MOSFET的基本概念

N沟道与P沟道MOSFET基本原理与区别 学习MOSFET时的简单笔记作为个人总结,仅供学习参考,实际电路设计请直接略过!!! 文章目录 N沟道与P沟道MOSFET基本原理与区别前言一、MOSFET ?二、N沟道MOS管原理三、P沟…

TCP/UDP模型:2024/2/29

作业1&#xff1a;TCP模型 服务器端&#xff1a; #include <myhead.h> #define SER_IP "192.168.199.129" #define SER_PORT 8899int main(int argc, const char *argv[]) {//1.创建用于连接的套接字文件int sfdsocket(AF_INET,SOCK_STREAM,0);if(sfd-1){per…

【Javascript编程实操02】1、判断一个年份是闰年还是平年 2、找到三个数中最小的数

目录 前言 1、判断一个年份是闰年还是平年 原理&#xff1a; 代码&#xff1a; 实现效果&#xff1a; 2、找到三个数中最小的数 流程图&#xff1a; 代码&#xff1a; 实现效果&#xff1a; 总结 前言 本次继续针对Javascript阶段的if...else...的实操练习&#xff0…

【MySQL】SQL 入门和 DDL

1. 通用语法 SQL语句可以单行或多行书写&#xff0c;以分号结尾SQL语句可以使用空格/缩进来增强语句的可读性MySQL数据库的SQL语句不区分大小写&#xff0c;关键字建议使用大写注释&#xff1a; 单行注释&#xff1a;-- 注释内容 或 # 注释内容多行注释&#xff1a;/* 注释内容…

探索JavaScript中的构造函数,巩固你的JavaScript基础

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【Unity实战】UGUI和Z轴排序那点事儿

如果读者是从Unity 4.x时代过来的&#xff0c;可能都用过NGUI这个插件&#xff08;后来也是土匪成了正规军&#xff09;&#xff0c;NGUI一大特点是可以靠transform位移的Z值进行遮挡排序&#xff0c;然而这个事情在UGUI成了难题&#xff08;Sorting Layer、Inspector顺序等因素…

波奇学Linux:共享内存

进程通信的前提&#xff1a;不同的进程看到同一份的资源 直接原理:同一块物理内存映射到不同进程的共享区 共享内存拆解&#xff1a; 1.申请内存&#xff0c;通过页表映射到进程地址空间 2.返回首地址&#xff0c;便于进程利用 3.释放共享内存&#xff0c;去关联 4.内存的申请…

如何使用Docker部署IT-Tools并结合内网穿透实现公网访问本地工具箱服务

作为程序员&#xff0c;在日常工作中&#xff0c;需要借助一些工具来提高我们工作效率&#xff0c;IT-Tools是为开发人员度身打造的一套便捷在线工具。它提供全面功能&#xff0c;使开发者能以更高效方式完成任务。经由IT-Tools&#xff0c;开发人员能轻松应对各类技术挑战&…

数据结构--树的遍历

数据结构--树的遍历 1. 前序中序后序遍历2. 前序中序后序遍历代码 1. 前序中序后序遍历 2. 前序中序后序遍历代码 /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */// 前序遍历顺序&#xff1…

Sora技术原理解析

1.Sora简介 Sora是一个基于大规模训练的文本控制视频生成扩散模型。 Sora能够生成高达1分钟的高清视频&#xff0c;涵盖广泛的视觉数据类型和分辨率。 Sora使用简单的文本描述&#xff0c;使得视频创作变得前所未有的简单和高效。 Sora的一些能力&#xff1a; Text-to-video…

爬取一人之下所有图片的uzr以及源代码

import requests from lxml import etree import json import os from urllib import request# 设置Bing搜索URL和请求头 url https://cn.bing.com/images/search?q%E4%B8%80%E4%BA%BA%E4%B9%8B%E4%B8%8B%E5%9B%BE%E7%89%87&formIQFRML&first1&cw1177&ch693 …

Gophish+EwoMail 自建钓鱼服务器

GophishEwoMail 自建钓鱼服务器 文章目录 GophishEwoMail 自建钓鱼服务器1.前提准备2.搭建EwoMail邮件服务器1&#xff09;Centos7 防火墙操作2&#xff09;设置主机名3&#xff09;host配置4&#xff09;安装EwoMail5&#xff09;获取DKIM6&#xff09;端口服务介绍7&#xff…