C++设计模式 - 创建型模式之工厂模式

news2024/11/18 15:38:44

文章目录

  • C++设计模式 - 创建型模式之工厂模式
      • 接口和针对接口编程
    • 1. 简单工厂模式
      • 适用场合
      • UML
      • 代码示例
    • 2. 工厂方法模式
      • 适用场合
      • UML
      • 代码示例
    • 3. 抽象工厂模式
      • 适用场合
      • UML
      • 代码示例
    • 总结

C++设计模式 - 创建型模式之工厂模式

工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。听上去差不多,都是工厂模式。

工厂模式的主要作用是封装对象的创建,分离对象的创建和操作过程,用于批量管理对象的创建过程,便于程序的维护和扩展

接口和针对接口编程

接口从语法层面来说,是纯虚类。从软件设计的意义来说,通常用接口来定义类的外观,约定了实现类应该要实现的功能。封装变化——即隔离变化。从软件的整体结构来看,只要接口不变,内部实现不会影响到外部应用,从而使得系统更灵活,具有更好的扩展性和可维护性。

1. 简单工厂模式

它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。有点抽象,举个例子就明白了。有一家生产处理器核的厂家,它只有一个工厂,能够生产两种型号的处理器核。客户需要什么样的处理器核,一定要显示地告诉生产工厂。

适用场合

在程序中,需要创建的对象很多,导致对象的构建复杂时,需要使用简单工厂模式;
由于对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。

UML

在这里插入图片描述

代码示例

#include <bits/stdc++.h>

using std::cout;
using std::endl;

//
//简单工厂模式
//


typedef enum PhoneTypeTag {
    MI_PHONE,
    IPHONE_PHONE,
    HUAWEI_PHONE
} PhoneType;


//产品抽象基类 AbstractProduct
class Phone {
    //添加虚析构函数!
public:
    virtual void type() = 0;//代表共有属性
};

//
//具体的产品类
//

class MiPhone : public Phone {
public:
    void type() override {
        cout << "I'm XiaoMi Phone !" << endl;
    }
};

class IPhone : public Phone {
public:
    void type() override {
        cout << "I'm IPhone !" << endl;
    }
};

class HuaweiPhone : public Phone {
public:
    void type() override {
        cout << "I'm Huawei Phone !" << endl;
    }
};

//工厂类 手机代工厂
class PhoneFactory {
public:
    //根据产品信息创建具体的产品类示例,返回一个抽象产品类
    std::shared_ptr<Phone> MakePhone(const PhoneType type) {
        switch (type) {
            case PhoneType::MI_PHONE:
                return std::make_shared<MiPhone>();
            case PhoneType::IPHONE_PHONE:
                return std::make_shared<IPhone>();
            case PhoneType::HUAWEI_PHONE:
                return std::make_shared<HuaweiPhone>();
            default:
                return nullptr;
        }
    }

};

int main() {
    PhoneFactory phoneFactory;
    std::shared_ptr<Phone> m_phone = nullptr;

    m_phone = phoneFactory.MakePhone(PhoneType::MI_PHONE);
    m_phone->type();

    m_phone = phoneFactory.MakePhone(PhoneType::IPHONE_PHONE);
    m_phone->type();

    m_phone = phoneFactory.MakePhone(PhoneType::HUAWEI_PHONE);
    m_phone->type();

    //动态绑定
    //m_phone = std::make_shared<MiPhone>();
    //m_phone->type();

    return 0;
}

代码运行输出结果如下:

I'm XiaoMi Phone !
I'm IPhone !
I'm Huawei Phone !
  • 主要特点:产品创建过程在工厂类中完成,当增加新产品时,需要修改工厂类。使用简单工厂模式,我们只需要知道具体的产品型号就可以创建一个产品。
  • 缺点:工厂类集中了所有产品类的创建逻辑,如果产品量较大,会使得工厂类变的非常臃肿。

2. 工厂方法模式

  • 其实这才是正宗的工厂模式,简单工厂模式只是一个简单的对创建过程封装。

  • 和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂

在代码实现上,工厂方法模式在简单工厂模式的基础上增加对工厂的基类抽象,不同的产品创建采用不同的工厂创建(从工厂的抽象基类派生),这样创建不同的产品过程就由不同的工厂分工解决:FactoryA专心负责生产ProductA,FactoryB专心负责生产ProductB,FactoryA和FactoryB之间没有关系;如果到了后期,如果需要生产ProductC时,我们则可以创建一个FactoryC工厂类,该类专心负责生产ProductC类产品。

适用场合

工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅提供具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

UML

在这里插入图片描述

代码示例

#include <bits/stdc++.h>

using std::cout;
using std::endl;

//
//工厂方法模式
//

//产品抽象基类 AbstractProduct
class Phone {
    //添加虚析构函数!
public:
    virtual void type() = 0;//代表共有属性
};

//
//具体的产品类
//

class MiPhone : public Phone {
public:
    void type() override {
        cout << "I'm XiaoMi Phone !" << endl;
    }
};

class IPhone : public Phone {
public:
    void type() override {
        cout << "I'm IPhone !" << endl;
    }
};

class HuaweiPhone : public Phone {
public:
    void type() override {
        cout << "I'm Huawei Phone !" << endl;
    }
};

//抽象工厂类,提供一个创建接口
class PhoneFactory {
public:
    //提供创建产品实例的接口,返回抽象产品类
    virtual std::shared_ptr<Phone> MakePhone() = 0;
};

//具体的创建工厂类,使用抽象工厂类提供的接口,各具体的工厂去创建具体的产品实例
class MiPhoneFactory : public PhoneFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<MiPhone>();
    }
};

class IPhoneFactory : public PhoneFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<IPhone>();
    }
};

class HuaWeiPhoneFactory : public PhoneFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<HuaweiPhone>();
    }
};


int main() {
    std::shared_ptr<Phone> m_pPhone = nullptr;

    m_pPhone = MiPhoneFactory().MakePhone();
    m_pPhone->type();

    m_pPhone = IPhoneFactory().MakePhone();
    m_pPhone->type();

    m_pPhone = HuaWeiPhoneFactory().MakePhone();
    m_pPhone->type();

    return 0;
}
  • 该模式相对于简单工厂模式的优势在于:便于后期产品种类的扩展。如果需要增加新的产品类,只需要扩展一个相应的工厂类即可。
  • 缺点:产品类数据较多时,需要实现大量的工厂类,这无疑增加了代码量。
工厂方法减轻了工厂类的负担,新增一种“手机”只需添加一个特定的“手机工厂”即可,这就符合了开放闭合原则:

3. 抽象工厂模式

  • 工厂方法自然比简单工厂更加灵活,但当业务有所变更时,比如需要添加“手机”的周边产品——“电脑”呢?这时候我们就需要一个更复杂的模式——抽象工厂

  • 抽象工厂是一个产品簇的概念,一个工厂可以生产多种业务相关的产品。我们在工厂方法的基础上扩充一下代码:定义一个抽象工厂接口AbstractFactory,通过不同的方法生产出一个“抽象”产品簇(Phone和PC)。回过头来再看工厂方法,事实上它就是抽象工厂最简单的一种场景设计——只生成一种产品。

  • 抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。

适用场合

工厂方法模式适用于产品种类结构单一的场合,为一类产品提供接口;
而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组(有多个种类)相关的产品,为它们提供创建的接口。

UML

在这里插入图片描述

代码示例

#include <bits/stdc++.h>

using std::cout;
using std::endl;

//
//抽象工厂模式
//

//手机产品抽象基类 AbstractProduct
class Phone {
    //添加虚析构函数!
public:
    virtual void type() = 0;//代表共有属性
};

//
//具体的手机产品类
//

class MiPhone : public Phone {
public:
    void type() override {
        cout << "I'm XiaoMi Phone !" << endl;
    }
};

class IPhone : public Phone {
public:
    void type() override {
        cout << "I'm IPhone !" << endl;
    }
};

class HuaweiPhone : public Phone {
public:
    void type() override {
        cout << "I'm Huawei Phone !" << endl;
    }
};


//PC产品抽象基类 AbstractProduct
class PC {
    //添加虚析构函数!
public:
    virtual void type() = 0;//代表共有属性
};

//
//具体的手机产品类
//

class MiPC : public PC {
public:
    void type() override {
        cout << "I'm XiaoMi PC !" << endl;
    }
};

class MACPC : public PC {
public:
    void type() override {
        cout << "I'm MAC PC !" << endl;
    }
};

class HuaweiPC : public PC {
public:
    void type() override {
        cout << "I'm Huawei PC !" << endl;
    }
};



//抽象工厂类,提供一个创建接口,其中增加PC产品接口
class AbstractFactory {
public:
    //提供创建产品实例的接口,返回抽象产品类
    virtual std::shared_ptr<Phone> MakePhone() = 0;
    virtual std::shared_ptr<PC> MakePC() = 0;
};



//具体的创建工厂类,使用抽象工厂类提供的接口,各具体的工厂去创建具体的产品实例
class MiFactory : public AbstractFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<MiPhone>();
    }

    std::shared_ptr<PC> MakePC() override{
        return std::make_shared<MiPC>();
    }
};

class IPhoneFactory : public AbstractFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<IPhone>();
    }
    std::shared_ptr<PC> MakePC() override{
        return std::make_shared<MACPC>();
    }
};

class HuaWeiFactory : public AbstractFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<HuaweiPhone>();
    }
    std::shared_ptr<PC> MakePC() override{
        return std::make_shared<HuaweiPC>();
    }
};

//另外一个代工厂,生产MiPhone和MAC
class OdmFactory : public AbstractFactory {
public:
    std::shared_ptr<Phone> MakePhone() override {
        return std::make_shared<MiPhone>();
    }
    std::shared_ptr<PC> MakePC() override{
        return std::make_shared<MACPC>();
    }
};



int main()
{
    std::shared_ptr<Phone> m_pPhone = nullptr;
    std::shared_ptr<PC> m_pPC = nullptr;

    MiFactory miFactory;
    IPhoneFactory iPhoneFactory;
    HuaWeiFactory huaWeiFactory;
    OdmFactory odmFactory;

    m_pPhone = miFactory.MakePhone();
    m_pPC = miFactory.MakePC();
    m_pPhone->type();
    m_pPC->type();

    m_pPhone = iPhoneFactory.MakePhone();
    m_pPC = iPhoneFactory.MakePC();
    m_pPhone->type();
    m_pPC->type();

    m_pPhone = huaWeiFactory.MakePhone();
    m_pPC = huaWeiFactory.MakePC();
    m_pPhone->type();
    m_pPC->type();

    m_pPhone = odmFactory.MakePhone();
    m_pPC = odmFactory.MakePC();
    m_pPhone->type();
    m_pPC->type();


    return 0;
}

代码输出如下:

I'm XiaoMi Phone !
I'm XiaoMi PC !
I'm IPhone !
I'm MAC PC !
I'm Huawei Phone !
I'm Huawei PC !
I'm XiaoMi Phone !
I'm MAC PC !

在抽象工厂模式中,增加新的产品族很方便(如可以将IPhone和HuaWeiPC作为一个产品系列,只用增加一个工厂即可),但是增加新的产品等级结构很麻烦(如,增加键盘作为新的产品,那么不仅需要增加新的产品类,同时各个工厂也需要进行对应的调整,将键盘这一产品增加进去)。

总结

工厂模式最直观的理解是,减少new创建对象的方式,用接口的方式来返回一个对象,而new创建的方式被封装了

  • 简单工厂:调用者只需使用单例工厂就可获取同一范畴的所有产品

  • 工厂方法:调用者并不知道它在运行时会获取何种产品,只知道某个特定的工厂能生成出满足需求的产品

  • 抽象工厂:调用者可以在运行时从特定的工厂中获得所有信息相关的产品簇(可以对产品进行组合)

工厂方法模式和抽象工厂模式区别:区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构,抽象工厂模式针对的是面向多个产品等级结构的。

是否可以这样理解呢:工厂方法模式生产一种产品,抽象工厂模式生产一系列产品,构成的是一个生态

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

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

相关文章

【Linux】信号量(基于环形队列的生产消费模型)

文章目录 POSIX信号量一、什么是信号量二、信号量接口1.初始化信号量2.销毁信号量3.申请信号量&#xff08;等待信号量&#xff09;4.释放信号量&#xff08;发布信号量&#xff09; 基于环形队列的生产消费模型一、结构介绍二、理论讲解三、代码实现 总结 POSIX信号量 POSIX信…

C语言之操作符详解

本章重点 1. 各种操作符的介绍 2. 表达式求值 给大家提到一些操作符&#xff0c;下面我们来给大家详细介绍 首先看算术操作符&#xff0c;其他几个都没什么可讲的我们来重点看一下/&#xff08;除法&#xff09; 整数除法&#xff08;除号的两端都是整数&#xff09; 浮点…

【漏洞复现】Apache RocketMQ 命令注入漏洞(CVE-2023-33246)

文章目录 前言声明一、漏洞描述二、漏洞危害三、影响版本四、环境搭建五、漏洞复现六、修复建议 前言 RocketMQ 是阿里巴巴在2012年开发的分布式消息中间件&#xff0c;专为万亿级超大规模的消息处理而设计&#xff0c;具有高吞吐量、低延迟、海量堆积、顺序收发等特点。同时它…

Shell脚本查询进程并kill进程(集群版)

记录&#xff1a;454 场景&#xff1a;使用Shell脚本查询进程并kill进程。使用Shell脚本远程执行脚本查询进程并kill进程。 版本&#xff1a;CentOS Linux release 7.9.2009。 1.使用Shell脚本查询进程并kill进程 1.1脚本 脚本名称&#xff1a;zk-kill_pid.sh 脚本内容&a…

从ROS1到ROS2无人机编程实战指南

亲爱的读者们&#xff0c;我今天非常荣幸地向大家推荐一本本人的全新力作——《从ROS1到ROS2无人机编程实战指南》。这本书站在初学者的角度&#xff0c;从入门到进阶&#xff0c;再到实战&#xff0c;循序渐进&#xff0c;是学习ROS1和ROS2的最佳选择。如今已在全国范围内上市…

Java spring boot 全解Camunda 7,从 0 到 1 构建工作流平台——第一节:各个开源框架对比

目录 1. Camunda 介绍2. Camunda 选型说明2.1 osworkflow2.2 jbpm2.3 ActivitiActiviti介绍各个版本的优缺点 2.4 flowable2.5 camundacamunda介绍主流版本介绍 2.6 n8n.io2.7 为什么选 camunda ? camunda7.x 还是 camunda 8.x &#xff1f;为什么选 camunda&#xff1f;camun…

碳排放预测模型 | Python实现基于机器学习回归分析的碳排放预测模型——数据可视化和探索

文章目录 效果一览文章概述研究内容环境准备源码设计学习总结参考资料效果一览 文章概述 碳排放预测模型 | Python实现基于机器回归分析的碳排放预测模型——数据可视化和探索 目标是测试所选特征对分析的重要性,检测异常值的存在并准备数据以供进一步分析。 </

Netty实战(十二)

预置的ChannelHandler和编解码器&#xff08;二&#xff09;HTTPS、WebSocket的添加使用和大型数据写入以及几种常见的序列化 一、基于Netty的HTTPS程序1.2 使用HTTPS2.3 WebSocket 二、空闲连接和超时三、 解码基于分隔符的协议和基于长度的协议3.1 基于分割符的协议3.2 基于长…

策 略 模 式「指 鼠 为 鸭」

前言 大家好&#xff0c;我是 god23bin&#xff0c;今天我们来介绍下设计模式中的一个重要的设计模式——策略模式。 当涉及到某个行为或算法有多个变体时&#xff0c;策略模式是一种常见的设计模式。它允许在运行时选择使用不同的策略&#xff0c;而无需修改现有代码。 现在…

OneFormer:规则通用图像分割的一个Transformer

文章目录 OneFormer: One Transformer to Rule Universal Image Segmentation摘要本文方法实验结果 OneFormer: One Transformer to Rule Universal Image Segmentation 摘要 通用图像分割并不是一个新概念。过去统一图像分割的尝试包括场景解析、全景分割&#xff0c;以及最…

【工具】SecureCR-8.5下载、安装激活和使用教程(包含常用设置)

目录 一、安装包下载 二、安装教程 三、激活操作 四、使用教程 五、常用设置 一、安装包下载 SecureCRT8.5安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1yy677I99ln_3evoHc5dMXg 提取码&#xff1a;9tyj 二、安装教程 1. 解压、双击进行安装 2. 安装进…

【LeetCode】136. 只出现一次的数 python

目录 题目描述 第一次刷题 第二次刷题 异或运算的规则 题目描述 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;…

[LeetCode周赛复盘] 第 106 场双周赛20230611

[LeetCode周赛复盘] 第 106 场双周赛20230611 一、本周周赛总结6461. 判断一个数是否迷人1. 题目描述2. 思路分析3. 代码实现 6425. 找到最长的半重复子字符串1. 题目描述2. 思路分析3. 代码实现 6426. 移动机器人1. 题目描述2. 思路分析3. 代码实现 6463. 找到矩阵中的好子集…

DHCP是什么?它有什么作用?其工作模式?工作原理?

目录 一、DHCP是什么&#xff1f;二、DHCP的作用&#xff1f;1. 在没有DHCP服务的网络中2. 在有DHCP服务的网络中 三、DHCP的工作模式简介四、DHCP的工作原理五、参考资料 一、DHCP是什么&#xff1f; DHCP是动态主机配置协议&#xff08;Dynamic Host Configuration Protocol…

Vue 封装ajax请求[接口]函数

在Vue项目开发当中&#xff0c;当有了后端提供的数据接口之后呢&#xff0c;就需要来为接口定义接口的请求函数&#xff0c;那么在去定义接口函数之前可以先来封装一个ajax请求函数&#xff1b;可能有的初学者在之前的一些篇目当中看到这个vue发起数据请求的不是使用axios的吗&…

3.MySQL表的增删改查(基础)

文章目录 ☕️1. CRUD☕️&#x1f375;2. 新增&#xff08;Create&#xff09;&#x1f375;&#x1f37c;2.1 单行数据 全列插入&#x1f37c;&#x1f37a;2.2 多行数据 指定列插入&#x1f37a;&#x1f378;2.3关于时间的插入格式(homework数据表)&#xff1a;&#x1f…

串口RS232、RS485最本质区别

由下图可看出不管是RS232还是RS485&#xff0c;其本质都是串口通信&#xff0c;只不过是串口通信电平上的变种而已。所以&#xff0c;我们首先从串口通信讲起。 1、串口通信 任何一种通信都要有物理接口和通信协议。串口通信物理接口如下图&#xff1a; 串口通信协议首先要约…

RBAC权限管理,Shiro实践

概念介绍 RBAC是指基于角色的访问控制&#xff08;Role-Based Access Control&#xff09;&#xff0c;它是一种广泛应用于计算机安全领域的访问控制机制。RBAC通过将用户分配到不同的角色&#xff0c;来控制用户对系统中资源的访问权限。 在RBAC中&#xff0c;每个角色都被…

LVS-DR群集部署

目录 一、LVS-DR数据包流向分析 二、 DR 模式的特点 总结 三、LVS-DR中的ARP问题 1.在局域网中具有相同的IP地址&#xff0c;势必会造成各服务器ARP通信的紊乱 2.路由器根据ARP表项&#xff0c;会将新来的请求报文转发给RealServer&#xff0c;导致Director的VIP失效 3.解…

openGauss5 企业版之yum方式安装

文章目录 1. 支持的架构和操作系统版本2. 使用限制3. 安装方式4. 使用说明 本章节主要介绍在openEuler 22.03 LTS操作系统上&#xff0c;通过yum命令一键安装openGauss数据库。 1. 支持的架构和操作系统版本 x86-64 openEuler 22.03 LTSARM64 openEuler 22.03 LTS 仅在openEu…