【C++】—— 工厂模式详解

news2025/1/17 14:11:02

目录

(一)工厂模式的特点

(二)工厂模式分类

1、简单工厂模式

2、工厂方法模式

3、抽象工厂模式

(三)总结与回顾


(一)工厂模式的特点

 1、优势

  • ⼯⼚模式是⼀种创建型设计模式, 它提供了⼀种创建对象的最佳⽅式;
  • 在⼯⼚模式中,我们创建对象时不会对上层暴露创建逻辑,⽽是通过使⽤⼀个共同结构来指向新创建的对象,以此实现创建-使⽤的分离。
2、缺点
尽管工厂模式在许多情况下是一种有用的设计模式,但它也有一些缺点需要考虑:
  • 除了原来的产品类和客户端代码外,还需要定义工厂接口具体工厂类等额外的类。这可能导致系统变得更加复杂,特别是当需要创建多个不同类型的对象时。
但是尽管工厂模式存在上述缺点,但在许多情况下它仍然是一种有用的设计模式。在实际应用中,我们需要权衡使用工厂模式带来的好处和缺点,并根据具体情况进行选择。

(二)工厂模式分类

工厂模式可以分为三种不同的类型:简单工厂模式工厂方法模式抽象工厂模式

1、简单工厂模式

简单⼯⼚模式实现由⼀个⼯⼚对象通过类型决定创建出来指定产品类的实例。
  • 假设有个⼯⼚能⽣产出⽔果,当客⼾需要产品的时候明确告知⼯⼚⽣产哪类⽔果,⼯⼚需要接收⽤⼾提供的类别信息,当新增产品的时候,⼯⼚内部去添加新产品的⽣产⽅式。
接下来,我们看代码演示:
#include<iostream>
#include <string>
#include <memory>

class Fruit{
    public:
        Fruit(){}
        virtual void show() = 0;
};
class Apple : public Fruit{
    public:
        Apple(){}
        virtual void show(){
            std::cout << "我是一个苹果" << std::endl;
        }
};

class Banana : public Fruit{
    public:
        Banana(){}
        virtual void show(){
            std::cout << "我是一个香蕉" << std::endl;
        }
};

class FruitFactory{
    public:
        static std::shared_ptr<Fruit> create(const std::string &name){
            if(name == "苹果"){
                return std::make_shared<Apple>();
            }
            else if(name == "香蕉"){
                return std::make_shared<Banana>();
            }
            else{
                return std::shared_ptr<Fruit>(); 
            }
        }
};
int main()
{
    std::shared_ptr<Fruit> fruit = FruitFactory::create("苹果");
    fruit->show();
    fruit = FruitFactory::create("香蕉");
    fruit->show();
    return 0;
}

运行结果如下:

【小结】
简单⼯⼚模式:通过参数控制可以⽣产任何产品

优点

  • 简单粗暴,直观易懂。使⽤⼀个⼯⼚⽣产同⼀等级结构下的任意产品
  缺点
  • 1. 所有东西⽣产在⼀起,产品太多会导致代码量庞⼤
  • 2. 开闭原则遵循(开放拓展,关闭修改)的不是太好,要新增产品就必须修改⼯⼚⽅法。

2、工厂方法模式

工厂方法模式定义一个创建对象的接口,但将实际的实例化延迟到子类中。每个子类都可以根据需要创建适合自身的对象。

  • 假设现在有A、B 两种产品,则开两个⼯⼚,⼯⼚ A 负责⽣产产品 A,⼯⼚ B 负责⽣产产品 B,⽤⼾只知道产品的⼯⼚名,⽽不知道具体的产品信息,⼯⼚不需要再接收客⼾的产品类别,⽽只负责⽣产产品。

接下来,我们还是看代码演示:

#include<iostream>
#include <string>
#include <memory>

class Fruit{
    public:
        Fruit(){}
        virtual void show() = 0;
};
class Apple : public Fruit{
    public:
        Apple(){}
        virtual void show(){
            std::cout << "我是一个苹果" << std::endl;
        }
};

class Banana : public Fruit{
    public:
        Banana(){}
        virtual void show(){
            std::cout << "我是一个香蕉" << std::endl;
        }
};


//工厂模式方法

class FruitFactory{
    public:
        virtual std::shared_ptr<Fruit> create() = 0;
};

class AppleFactory : public FruitFactory{
    public:
        virtual std::shared_ptr<Fruit> create(){
            return std::make_shared<Apple>();
        }
};

class BananaFactory : public FruitFactory{
    public:
        virtual std::shared_ptr<Fruit> create(){
            return std::make_shared<Banana>();
        }
};

int main()
{
    std::shared_ptr<FruitFactory> factory(new AppleFactory());
    std::shared_ptr<Fruit> fruit = factory->create();
    fruit->show();
    factory.reset(new BananaFactory());
    fruit = factory->create();
    fruit->show();
    return 0;
}

运行结果如下:

【小结】

⼯⼚⽅法:定义⼀个创建对象的接⼝,但是由⼦类来决定创建哪种对象,使⽤多个⼯⼚分别⽣产指定 的固定产品
优点
  • 1. 减轻了⼯⼚类的负担,将某类产品的⽣产交给指定的⼯⼚来进⾏
  • 2. 开闭原则遵循较好,添加新产品只需要新增产品的⼯⼚即可,不需要修改原先的⼯⼚类
缺点
  • 对于某种可以形成⼀组产品族的情况处理较为复杂,需要创建⼤量的⼯⼚类

⼯⼚⽅法模式通过引⼊⼯⼚等级结构,解决了简单⼯⼚模式中⼯⼚类职责太重的问题,但由于⼯⼚⽅法模式中的每个⼯⼚只⽣产⼀类产品,可能会导致系统中存在⼤量的⼯⼚类,势必会增加系统的开销。———— 由此就引入了抽象工厂模式。


3、抽象工厂模式

可以考虑将⼀些相关的产品组成⼀个产品族(位于不同产品等级 结构中功能相关联的产品组成的家族),由同⼀个⼯⼚来统⼀⽣产,这就是抽象⼯⼚模式的基本思想。

接下来,我们还是看代码演示:

#include<iostream>
#include <string>
#include <memory>

//产品类一:水果
class Fruit{
    public:
        Fruit(){}
        virtual void show() = 0;
};
class Apple : public Fruit{
    public:
        Apple(){}
        virtual void show(){
            std::cout << "我是一个苹果" << std::endl;
        }
};

class Banana : public Fruit{
    public:
        Banana(){}
        virtual void show(){
            std::cout << "我是一个香蕉" << std::endl;
        }
};


//产品类二:动物
class Animal {
    public:
        virtual void voice() = 0;
};

class Lamp: public Animal {
    public:
        void voice() override { std::cout << "咩咩咩\n"; }
};

class Dog: public Animal {
    public:
        void voice() override { std::cout << "汪汪汪\n"; }
};


class Factory {
    public:
        virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;
        virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};

class FruitFactory : public Factory {
    public:
        virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {
            return std::shared_ptr<Animal>();
        }
    virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {
        if (name == "苹果") {
            return std::make_shared<Apple>();
        }else if(name == "⾹蕉") {
            return std::make_shared<Banana>();
        }
        return std::shared_ptr<Fruit>();
    }
};

class AnimalFactory : public Factory {
    public:
        virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {
            return std::shared_ptr<Fruit>();
        }
        virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {
            if (name == "⼩⽺") {
                return std::make_shared<Lamp>();
            }else if(name == "⼩狗") {
                return std::make_shared<Dog>();
            }
            return std::shared_ptr<Animal>();
        }
};


class FactoryProducer {
    public:
        static std::shared_ptr<Factory> getFactory(const std::string &name) {
            if (name == "动物") {
                return std::make_shared<AnimalFactory>();
            }else {
                return std::make_shared<FruitFactory>();
            }   
        }
};


int main()
{
    std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("⽔果");
    std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");
    fruit->show();
    fruit = fruit_factory->getFruit("⾹蕉");
    fruit->show();

    std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动物");
    std::shared_ptr<Animal> animal = animal_factory->getAnimal("⼩⽺");
    animal->voice();
    animal = animal_factory->getAnimal("⼩狗");
    animal->voice();

    return 0;
}

运行结果如下:

【小结】

抽象⼯⼚:围绕⼀个超级⼯⼚创建其他⼯⼚。每个⽣成的⼯⼚按照⼯⼚模式提供对象。

抽象⼯⼚模式适⽤于⽣产多个⼯⼚系列产品衍⽣的设计模式,增加新的产品等级结构复杂,需要对原有系统进⾏较⼤的修改,甚⾄需要修改抽象层代码,违背了“开闭原则”。

 


(三)总结与回顾

以上便是本文关于工厂模式的全部内容,接下来简单回顾总结下本文都讲到了什么!!!

工厂模式是一种创建型设计模式,旨在封装对象的实例化过程,使得客户端代码与具体类的实例化过程解耦,从而提高代码的可维护性、可扩展性和灵活性;

优势:

  1. 解耦: 工厂模式能够将对象的创建和使用分离,降低了客户端与具体类之间的耦合度。

  2. 可维护性: 当需要修改或扩展具体类时,只需修改工厂类而不影响客户端代码,提高了系统的可维护性。

  3. 扩展性: 可通过增加新的具体工厂和具体产品来扩展系统,符合开闭原则。

  4. 代码复用: 工厂模式促进了代码的复用,因为客户端通过接口或基类与工厂类交互,而不直接与具体类交互。

适用场景:

  1. 对象的创建逻辑复杂: 当对象的创建涉及一系列复杂的步骤或条件判断时,使用工厂模式可以将这些复杂性封装起来。

  2. 需要根据条件动态创建对象: 当需要根据不同条件来创建不同类型的对象时,工厂模式是一个有效的选择。

  3. 系统需要更高的灵活性和可扩展性: 工厂模式允许系统在不修改客户端代码的情况下引入新的产品类和工厂类,提供了系统的可扩展性。

到此,本文的内容全部讲解结束。感谢大家的观看与支持!!!

 

 

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

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

相关文章

【大数据进阶第三阶段之Hue学习笔记】Hue的安装和使用

1、 Hue的安装 1.1 上传解压安装包 Hue的安装支持多种方式&#xff0c;包括rpm包的方式进行安装、tar.gz包的方式进行安装以及cloudera manager的方式来进行安装等&#xff0c;我们这里使用tar.gz包的方式来进行安装 Hue的压缩包的下载地址&#xff1a; http://archive.cloude…

C++|19.C++类与结构体对比

类和结构体 类和结构体本质上并没有太大区别。 但两者在默认上有所区别。 类默认成员变量是私有的&#xff0c;而结构体默认成员变量是公有的。 也就是说&#xff0c;对于一个类来说&#xff0c;会默认使用private去保护其内部成员变量使得无法直接访问到其内部的变量。 同时从…

CANoe中的AutoSequence

简单介绍&#xff1a; AutoSequence是一种简单的&#xff0c;快速的类似脚本的一个可视化自动脚本插件。使用起来非常方便&#xff0c;甚至在很多时候能够代替一些简单的脚本。 1&#xff1a;Automation工程的创建 &#xff08;1.1&#xff09;打开Automation插件,双击这个插…

TypeScript进阶(一)深入理解类和接口

✨ 专栏介绍 TypeScript是一种由微软开发的开源编程语言&#xff0c;它是JavaScript的超集&#xff0c;意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript&#xff0c;使其更适合大型项目和团队开发。 在TypeS…

【2024最新-python3小白零基础入门】No2.python基础语法

文章目录 1 编码2 标识符规则3 python保留字4 注释5 行与缩进6 多行语句7 数字(Number)类型8 字符串(String)9 空行10 等待用户输入11 同一行显示多条语句12 import 与 from...import 环境准备&#xff0c;打开pycharm,新建一个python文件 文件名称随便&#xff0c;可中文可英文…

golang 记录一次协程和协程池的使用,利用ants协程池来处理定时器导致服务全部阻塞

前言 在实习的项目中有一个地方遇到了需要协程池的地方&#xff0c;在mt推荐下使用了ants库。因此在此篇记录一下自己学习使用此库的情况。 场景描述 此服务大致是一个kafka消息接收、发送相关。接收消息&#xff0c;根据参数设置定时器进行重发。 通过这里新建kafka服务&a…

ffmpeg[学习(四)](代码实现) 实现音频数据解码并且用SDL播放

0、作者杂谈 CSDN大多数都是落后的&#xff0c;要么是到处复制粘贴的&#xff0c;对于初学者我来说困惑了很久&#xff0c;大多数CSDN文章都是使用旧的API &#xff0c;已经被否决了&#xff0c;于是我读一些官方文档&#xff0c;和一些开源项目音视频的输出过程&#xff0c;写…

CCSC,一种CPU架构

core-circuit-separate-computer 核与执行电路的分离&#xff0c;最初是为了省电。 用寄存器实现这种分离。 V寄存器控制着执行电路的供电&#xff0c;V0则不供电&#xff0c;进入省电模式&#xff1b;V1则供电&#xff0c;进入工作模式。 P寄存器是parameter-register&#xf…

Qt应用-实现图像截取功能类似QQ上传头像截取功能

本文演示利用Qt实现图像截取功能类似QQ上传头像截取功能。 效果如下,通过移动中间的裁剪区域可以获得一张裁剪后的图片。 目录

Open3D 搜索某个点的圆柱形邻域点云(11)

Open3D 搜索某个点的圆柱形邻域点云(11) 一、算法介绍二、算法实现1、代码2、结果一、算法介绍 具体而言,search_hybrid_vector_3d方法会以指定的查询点为中心,在给定的半径范围内搜索邻域点。还可以指定近邻点的数量阈值,这对于需要特定数量邻域点的应用非常有用,比如提…

安全技能讲座 - 便携式灭火器 (Portable Fire Extinguishers )

【Transcript 】 火灾随时随地都可能发生&#xff0c;而且毫无征兆。如果您在家中或工作中遇到火灾&#xff0c;便携式灭火器可以帮助您保护自己&#xff0c;并有可能将火灾扼杀在摇篮中。本课程将向您介绍便携式灭火器、其工作原理和使用方法。成功完成本课程后&#xff0c;您…

kubectl常用命令(主题篇)

上一篇是按照操作把全局性的命令给整理出来&#xff0c;但是在实际的使用中&#xff0c;经常需要对某一个主题进行操作&#xff0c;因此这一篇按照对应的主题进行一系列操作。 集群 查看集群基本信息 kubectl cluster-info namespace 命名空间 查看 kubectl get namespace k…

查看Linux系统内存、CPU、磁盘使用率和详细信息

一、查看内存占用 1、free # free -m 以MB为单位显示内存使用情况 [rootlocalhost ~]# free -mtotal used free shared buff/cache available Mem: 11852 1250 8668 410 1934 9873 Swap: 601…

大模型学习之书生·浦语大模型3——基于InternLM和LangChain搭建知识库

基于InternLM和LangChain搭建知识库 1 大模型开发范式 LLM的局限性 知识受限&#xff1a;最新知识无法实时获取专业能力有限&#xff1a;有广度无深度定制化成本高&#xff1a;训练成本高 RAG VS Finetune RAG&#xff1a; 无需重新训练组织外挂加入知识容易受基座模型的影响…

Linux中快速搭建RocketMQ测试环境

必要的文件下载 为什么选择RocketMQ | RocketMQ x86_64位JDK下载0jdk/8u391-b13 rocketmq二进制包下载-rocketmq-all-5.1.4-bin-release.zip 编译好的直接可用的dashboard【rocketmq-dashboard-1.0.0.jar】请在文章顶部下载 dashboard配套的配置文件【application.propert…

基于宝塔搭建Discuz!论坛

一、安装宝塔 我是在我的虚拟机上安装图的宝塔 虚拟机版本&#xff1a;Ubuntu 18.04 wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh 6dca892c安装完成之后在浏览器输入你的地址 https://你的域名&#xff08;或…

NX二次开发 Block UI 指定方位控件的应用

一、概述 NX二次开发中一般都是多个控件的组合&#xff0c;这里我首先对指定方位控件进行说明并结合选择对象控件&#xff0c;具体如下图所示。 二、实现功能获取方位其在选择面上原点的目标 2.1 在initialize_cb()函数中进行初始化&#xff0c;实现对象选择过滤面 //过滤平…

C++多态(超详解哦)

C多态 引言定义及实现多态的条件虚函数与虚函数的重写接口继承与实现继承函数重载&#xff0c;隐藏&#xff0c;重写的区别 抽象类多态的原理虚函数表&#xff08;虚表&#xff09;动态绑定与静态绑定 总结 引言 在生活中不乏这样的例子&#xff1a;成人与儿童在买票时会有不同…

FRPS配置服务端(腾讯云)、客户端(PC电脑Windows、树莓派Debian)并设置虚拟域名

1.服务端&#xff08;腾讯云&#xff09;&#xff1a;frps.ini [common] bind_port 7000 vhost_http_port8080 vhost_https_port44344 dashboard_port 7500 privilege_token your_password subdomain_host example.com use_encryption true encryption_method tls dashb…

oracle角色管理

常用角色 CONNECT,RESOURCE,DBA,EXP_FULL_DATABASE,IMP_FULL_DATABASE 1角色可以自定义&#xff0c;语法与创建用户一样 CREATE role role1 IDENTIFIED by 123; 2授权权限给角色 --自定义角色 CREATE role role1 IDENTIFIED by 123; --授权权限给角色 GRANT create view, …