C++设计模式——Abstract Factory Pattern抽象工厂模式

一、抽象工厂模式的定义

抽象工厂模式是一种创建型设计模式,它提供了一种将相关/依赖对象组合在一起创建的方式,而无需指定它们的具体类。

抽象工厂模式与工厂方法模式的区别:

工厂方法模式将对象的创建过程延迟到子类中,允许用户通过一个统一的接口来请求他们想要的具体产品,而无需知道产品的具体实现。在这个模式中,工厂类只负责生产同一系列的产品,但具体哪种产品由子类决定。

抽象工厂模式更进一步,它提供了一个接口,用于创建一系列相关的或相互依赖的对象,而不是单一对象。抽象工厂封装了产品系列的创建逻辑,客户端不需要知道如何创建具体的产品对象,只需要关心最终能得到哪些产品。这种模式通常用于解决产品集的变化而无需修改客户端代码的情况。

当需要面对多个产品等级结构时,更推荐使用抽象工厂模式。

抽象工厂模式在现实生活中的抽象实例:

汽车制造:对于每个品牌的汽车,公司都有不同的组件供应商,例如发动机、座椅和轮胎供应商。在抽象工厂模式中,汽车制造公司充当工厂角色,而不同品牌的汽车和不同的组件供应商充当具体产品。

美食餐厅:餐厅可以提供多种类型的饮料和食物,比如咖啡和披萨。每种类型的饮料和食物都有不同的原料供应商。在抽象工厂模式中,餐厅充当工厂角色,而不同类型的饮料和食物以及不同的原料供应商充当具体产品。

电子产品制造:假设有一家电子产品制造公司,对于每种电子产品,公司都有不同的组件供应商,例如显示屏、处理器和电池供应商。在抽象工厂模式中,电子产品制造公司充当工厂角色,而不同类型的电子产品和不同的组件供应商充当具体产品。

二、抽象工厂模式的结构

抽象工厂模式主要包含以下组件:

1.抽象工厂(AbstractFactory):它声明了创建一系列具有相同接口的对象的方法,这些对象代表不同的产品。

2.具体工厂(ConcreteFactory):是抽象工厂的具体实现,负责创建具体产品对象。每个具体工厂对应了一系列的具体产品。

3.抽象产品(AbstractProduct):它声明了产品对象的接口,包含了创建产品的公共方法。

4.具体产品(ConcreteProduct):是抽象产品的具体实现。

组件之间的工作步骤如下:

1.定义一个抽象工厂类, 这个类声明了一系列产品的创建方法,但不提供方法的具体代码实现。

2.代码在特定的上下文环境中调用具体工厂对象来负责创建一系列的产品。

3. 当客户端需要一个产品时,它向抽象工厂发送请求。抽象工厂根据当前需求选择合适的具体工厂,并由该工厂返回所需的产品实例。

抽象工厂模式将具体产品的创建和使用进行了解耦,使得客户端与具体产品的实现分离,能够很方便地替换不同的产品系列。

对应UML类图:

三、抽象工厂模式代码样例

#include <iostream>
using namespace std;
// Abstract Product A
class AbstractProductA {
public:
    virtual void operationA() = 0;
};
// Concrete Product A1
class ProductA1 : public AbstractProductA {
public:
    void operationA() override {
        cout << "Product A1 operation" << endl;
    }
};
// Concrete Product A2
class ProductA2 : public AbstractProductA {
public:
    void operationA() override {
        cout << "Product A2 operation" << endl;
    }
};
// Abstract Product B
class AbstractProductB {
public:
    virtual void operationB() = 0;
};
// Concrete Product B1
class ProductB1 : public AbstractProductB {
public:
    void operationB() override {
        cout << "Product B1 operation" << endl;
    }
};
// Concrete Product B2
class ProductB2 : public AbstractProductB {
public:
    void operationB() override {
        cout << "Product B2 operation" << endl;
    }
};
// Abstract Factory
class AbstractFactory {
public:
    virtual AbstractProductA* createProductA() = 0;
    virtual AbstractProductB* createProductB() = 0;
};
// Concrete Factory 1
class ConcreteFactory1 : public AbstractFactory {
public:
    AbstractProductA* createProductA() override {
        return new ProductA1();
    }
    AbstractProductB* createProductB() override {
        return new ProductB1();
    }
};
// Concrete Factory 2
class ConcreteFactory2 : public AbstractFactory {
public:
    AbstractProductA* createProductA() override {
        return new ProductA2();
    }
    AbstractProductB* createProductB() override {
        return new ProductB2();
    }
};
int main() {
    AbstractFactory* factory1 = new ConcreteFactory1();
    AbstractProductA* productA1 = factory1->createProductA();
    AbstractProductB* productB1 = factory1->createProductB();
    productA1->operationA();
    productB1->operationB();
    AbstractFactory* factory2 = new ConcreteFactory2();
    AbstractProductA* productA2 = factory2->createProductA();
    AbstractProductB* productB2 = factory2->createProductB();
    productA2->operationA();
    productB2->operationB();
    delete factory1;
    delete factory2;
    delete productA1;
    delete productB1;
    delete productA2;
    delete productB2;
    return 0;
}

运行结果:

Product A1 operation
Product B1 operation
Product A2 operation
Product B2 operation

四、抽象工厂模式的优缺点

抽象工厂模式的优点:

降低了客户端与具体产品的耦合度。

符合单一职责原则,每个具体工厂类只负责创建特定的产品。

隐藏了对象的创建过程,客户端不需要关心具体的对象创建细节,只需要通过工厂接口获取所需对象即可。

抽象工厂模式的缺点:

当产品族中需要增加新的产品时,既需要扩展抽象工厂的接口,又需要新增一个具体工厂类,大大增加了代码的维护成本。

当需要创建的产品种类非常多时,抽象工厂模式的类数量将急剧增加,导致系统难以维护和理解。

五、代码实战

模拟披萨的制作过程:

PizzaFactory:

NewYorkCheesePizza:bake() -> cut() -> box()

NewYorkPepperoniPizza:bake() -> cut() -> box()

ChicagoCheesePizza:bake() -> cut() -> box()

ChicagoPepperoniPizza:bake() -> cut() -> box()

#include <iostream>

class Pizza {
public:
    virtual void bake() = 0;
    virtual void cut() = 0;
    virtual void box() = 0;
};

class NewYorkCheesePizza : public Pizza {
public:
    void bake() override
    {
        std::cout << "Baking New York-style cheese pizza."
                << std::endl;
    }

    void cut() override
    {
        std::cout << "Cutting New York-style cheese pizza."
                << std::endl;
    }

    void box() override
    {
        std::cout << "Boxing New York-style cheese pizza."
                << std::endl;
    }
};

class NewYorkPepperoniPizza : public Pizza {
public:
    void bake() override
    {
        std::cout
            << "Baking New York-style pepperoni pizza."
            << std::endl;
    }

    void cut() override
    {
        std::cout
            << "Cutting New York-style pepperoni pizza."
            << std::endl;
    }

    void box() override
    {
        std::cout
            << "Boxing New York-style pepperoni pizza."
            << std::endl;
    }
};

class ChicagoCheesePizza : public Pizza {
public:
    void bake() override
    {
        std::cout << "Baking Chicago-style cheese pizza."
                << std::endl;
    }

    void cut() override
    {
        std::cout << "Cutting Chicago-style cheese pizza."
                << std::endl;
    }

    void box() override
    {
        std::cout << "Boxing Chicago-style cheese pizza."
                << std::endl;
    }
};

class ChicagoPepperoniPizza : public Pizza {
public:
    void bake() override
    {
        std::cout << "Baking Chicago-style pepperoni pizza."
                << std::endl;
    }

    void cut() override
    {
        std::cout
            << "Cutting Chicago-style pepperoni pizza."
            << std::endl;
    }

    void box() override
    {
        std::cout << "Boxing Chicago-style pepperoni pizza."
                << std::endl;
    }
};

class PizzaFactory {
public:
    virtual Pizza* createCheesePizza() = 0;
    virtual Pizza* createPepperoniPizza() = 0;
};

class NewYorkPizzaFactory : public PizzaFactory {
public:
    Pizza* createCheesePizza() override
    {
        return new NewYorkCheesePizza();
    }

    Pizza* createPepperoniPizza() override
    {
        return new NewYorkPepperoniPizza();
    }
};

class ChicagoPizzaFactory : public PizzaFactory {
public:
    Pizza* createCheesePizza() override
    {
        return new ChicagoCheesePizza();
    }

    Pizza* createPepperoniPizza() override
    {
        return new ChicagoPepperoniPizza();
    }
};

int main()
{
    PizzaFactory* newYorkFactory
        = new NewYorkPizzaFactory();
    Pizza* newYorkCheesePizza
        = newYorkFactory->createCheesePizza();
    Pizza* newYorkPepperoniPizza
        = newYorkFactory->createPepperoniPizza();

    PizzaFactory* chicagoFactory
        = new ChicagoPizzaFactory();
    Pizza* chicagoCheesePizza
        = chicagoFactory->createCheesePizza();
    Pizza* chicagoPepperoniPizza
        = chicagoFactory->createPepperoniPizza();

    newYorkCheesePizza->bake();
    newYorkCheesePizza->cut();
    newYorkCheesePizza->box();

    newYorkPepperoniPizza->bake();
    newYorkPepperoniPizza->cut();
    newYorkPepperoniPizza->box();

    chicagoCheesePizza->bake();
    chicagoCheesePizza->cut();
    chicagoCheesePizza->box();

    chicagoPepperoniPizza->bake();
    chicagoPepperoniPizza->cut();
    chicagoPepperoniPizza->box();

    delete newYorkFactory;
    delete newYorkCheesePizza;
    delete newYorkPepperoniPizza;
    delete chicagoFactory;
    delete chicagoCheesePizza;
    delete chicagoPepperoniPizza;

    return 0;
}

运行结果:

Baking New York-style cheese pizza.
Cutting New York-style cheese pizza.
Boxing New York-style cheese pizza.
Baking New York-style pepperoni pizza.
Cutting New York-style pepperoni pizza.
Boxing New York-style pepperoni pizza.
Baking Chicago-style cheese pizza.
Cutting Chicago-style cheese pizza.
Boxing Chicago-style cheese pizza.
Baking Chicago-style pepperoni pizza.
Cutting Chicago-style pepperoni pizza.
Boxing Chicago-style pepperoni pizza.

六、参考阅读

https://www.fluentcpp.com/2022/04/06/design-patterns-vs-design-principles-abstract-factory/

https://www.geeksforgeeks.org/abstract-factory-pattern-c-design-patterns/

https://sourcemaking.com/design_patterns/abstract_factory/cpp/before-after

https://www.scaler.com/topics/design-patterns/creational-design-pattern/

抽象工厂模式(附C++代码示例) 阅读详情

相关推荐

【C++实战㊵】C++抽象工厂模式:解锁高效对象创建的密钥

本文聚焦 C++ 抽象工厂模式实战,先阐释其定义 —— 提供创建相关或依赖对象的接口,无需指定具体类,介绍产品族创建、跨平台开发等适用场景,解析抽象工厂、具体工厂等组成结构。接着给出产品族 A、B 的实现代码,对比其与工厂方法模式,说明产品族扩展方法。还分享退化场景、与依赖注入结合、线程安全处理等实战技巧,最后通过跨平台 UI 组件库项目,展示模式在多平台组件创建与测试中的应用,助力开发者掌握该模式高效创建对象的能力。

邓邓子的博客 1202

ESP32驱动Xbox Series X手柄的BLE协议实现

蓝牙低功耗(BLE)是嵌入式设备无线交互的核心技术,其GATT协议架构支持自定义服务与特征值通信,广泛应用于游戏外设、工业遥控等场景。Xbox Series X手柄采用非标准私有BLE协议,需深度解析输入报告(64字节)、输出控制(振动/LED)及固件兼容性约束。该方案依托ESP32平台与NimBLE 2.1.0+协议栈,解决MTU协商、PHY配置与HCI事件同步等关键问题,实现125Hz实时输入采集与毫秒级振动反馈。适用于机器人遥操作、ROS2终端、LVGL交互界面等工程实践,是私有BLE设备逆向集成的典

weixin_42610671的博客 710

stm32 + freertos + c++混合编程方法

其他一些资料上面,c++配置成--cpp11或者-cpp 都是把工程配置成c++。三、添加cpp文件,我们调用cpp文件里面的接口函数,不需要修改main.c后缀名。2、配置工程编译时候是--c99,是因为工程里面FreeRTOS是c语言,c++模式会报错。我们这里是默认c,编写的c++文件,单独选择--cpp编译,这在后面配置!c++是面向对象编程,对于一些项目来说,c++编程更加合适!stm32cubemax配置,这里就不写了,配置资料比较多。这里就是让cpp文件在c++下编译。最后,编程成功,点亮!

yuhu0012的博客 2629

GNSS接收机性能测试指标详解:TTFF、位置精度、灵敏度等关键参数如何评估

本文详细解析了GNSS接收机性能测试的关键指标,包括首次定位时间(TTFF)、位置精度、灵敏度等,帮助工程师系统评估接收机性能。通过多频段协同定位和载波相位测试等技术,提升定位精度至亚米级。同时,介绍了灵敏度测试的极限挑战和授时精度的专业测试方案,为GNSS接收机的性能优化提供实用指导。

cuda7parallel的博客 963

macOS Monterey官方镜像高速下载指南(附迅雷链接+兼容性清单)

本文提供macOS Monterey官方镜像的高速下载指南,重点介绍利用迅雷等工具加速下载官方安装包的有效方法。同时,详细列出了系统兼容性清单,帮助用户在下载前确认设备支持,并分享了从下载、验证到安全安装的完整流程与常见问题解决方案。

j7k8l的博客 2182

学术报告系列(二) - 智能自主作业机器人感知与控制技术及发展趋势

收集整理于2022年模式识别高峰论坛湖南大学王耀南院士报告(报名题目:智能自主作业机器人感知与控制技术及发展趋势)

Make something people want. 4696

new delete 详解

常规的new 和 delete 当需要内存时,可以使用new申请内存,但在用完内存时应当使用delete 去归还内存,以防止内存泄漏,具体使用方案见下面代码: int* ps = new int ; // 使用new 申明变量空间 ... ... delete ps ; '// delete 删除所申明的变量空间 上述代码将删除ps 指针指向的内存空间,但不会删除指针本身,即仍然可以使用该指针去指向其他int 类型的变量。new 和 delete 一定需要成对的使用否则极易发生内存泄漏。 注意:不

qq_42138448的博客 6938

超详细!Linux 服务器 6 大核心性能测试(附自动脚本 + 结果分析秘籍)---Linux 服务器性能测试文档

本文档旨在提供 Linux 服务器的 CPU、内存和磁盘性能测试方案,包括详细的测试大纲、操作步骤以及一键化测试脚本,帮助管理员快速评估服务器性能状况。通过以上测试方案,可以全面评估 Linux 服务器的 CPU、内存和磁盘性能,为系统优化、容量规划和问题排查提供重要参考依据。使用 sysbench 进行 CPU 基准测试。使用 sysbench 测试内存读写性能。使用 fio 工具进行更全面的磁盘测试。使用 dd 命令测试磁盘顺序读写性能。使用 dd 命令测试内存读写速度。记录磁盘 IO 性能。

jundao1997的专栏 380

【时时三省】tessy 进入调试模式 教程

山不在高,有仙则名。水不在深,有龙则灵。----优快云 时时三省。

时时三省的博客 771

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: C++设计模式——Factory Method工厂方法模式
下一篇: C++设计模式——Singleton单例模式
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员与背包客_CoderZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值