C++设计模式|创建型 2.工厂模式

news2025/2/2 19:56:41

1.简单工厂思想

简单工厂模式不属于23种设计模式之⼀,更多的是⼀种编程习惯。它的核心思想是将产品的创建过程封装在⼀个⼯⼚类中,把创建对象的流程集中在这个⼯⼚类⾥⾯。卡码网将其结构描述为下图所示的情况:

简单⼯⼚模式包括三个主要⻆⾊,⼯⼚类、抽象产品类、具体产品类。它们的职责如下:

  • ⼯⼚类:负责创建产品,根据传递的不同参数创建不同的产品示例。
  • 抽象产品类:由工厂类提供的接口,⽐如上图中的 Shape 接⼝,描述产品的通⽤⾏为。
  • 具体产品类:实现抽象产品接⼝或继承抽象产品类,⽐如上⾯的 Circle 类和 Square 类,具体产品通过简单⼯⼚类的 if-else 逻辑来实例化。

 简单工厂的优点是简化了客户端的操作,客户端可以调用工厂方法来获取具体产品,而无需直接与具体产品类交互,降低了耦合,但是有一个很大的问题就是不够灵活,如果需要添加新的产品,就需要修改工厂类的代码

2.什么是工厂模式?

简单工厂的思想中只有一个工厂类,用于创建所有的产品,如果需要添加新的产品,就需要修改工厂类的代码。而工厂模式引入了抽象工厂和具体工厂的概念,每个具体工厂只负责创建一个具体产品,添加新产品时只需要添加新的工厂类,支持扩展,复合开闭原则。

工厂方法模式分为以下几个角色:

  • 抽象工厂:一个接口,包含一个抽象的工厂方法,该方法用于创建产品对象
  • 具体工厂:实现抽象工厂接口,创建具体的产品。
  • 抽象产品类:定义产品的接口。
  • 具体产品类:实现抽象产品接口,是工厂创建的对象。

 工厂模式的示意图如下图所示,实际的生产系统所管理的是对应的工厂,工厂负责产品的生产。当有具体需求传入时,生产提供根据需求创建对应的工厂,这些工厂去完成需求产品的生产。在有新的产品时,只需要扩展一下产品的内容及其对应的工厂即可,原来的代码无需更改,只需要往里面添加新的模块即可,非常灵活。

 3.C++工厂模式

【设计模式专题之工厂方法模式】2.积木工厂 (kamacoder.com)icon-default.png?t=N7T8https://kamacoder.com/problempage.php?pid=1076

题目描述:

小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木,请你帮他设计一个积木工厂系统,记录积木生产的信息。

输入描述

输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示生产的次数。 

接下来的 N 行,每行输入一个字符串和一个整数,字符串表示积木的类型。积木类型分为 "Circle" 和 "Square" 两种。整数表示该积木生产的数量

输出描述

对于每个积木,输出一行字符串表示该积木的信息。

输入示例

3
Circle 1
Square 2
Circle 1

 输出示例

Circle Block
Square Block
Square Block
Circle Block

代码实现: 

先实现抽象产品类和具体产品类:

//抽象积木产品类,定义生产具体积木的接口produce()
class Block{
public:
    //写成纯虚函数,一方面将该类变成抽象类,另一方面方便具体产品类实现多态
    virtual void produce() = 0;
};


//具体圆形积木产品类
class CircleBlock: public Block{
public:
    //重写父类虚函数,使用override关键字编译器会检查重写是否正确,不是非要加
    void produce() override {
        cout<<"Circle Block"<<endl;
    }
};

//具体方形积木产品类
class SquareBlock: public Block{
public:
    //重写父类虚函数
    void produce() override
    {
        cout<<"Square Block"<<endl;
    }
};

再实现抽象工厂类和具体工厂类,其中具体工厂类要调用具体产品的生产函数,所以工厂类写在了产品类的后面:

//抽象工厂类,提供一个抽象的接口用于创建对象。具体哪种对象还得用多态实现
class BlockFactory{
public:
    //抽象的接口。 使用积木的基类指针作为返回值,其可以接收圆形或方形的积木对象(C++多态允许)
    virtual Block* createBlock() = 0;
};

//具体圆形积木工厂类
class CircleBlockFactory:public BlockFactory{
public:  
    //重写接口函数
    Block* createBlock() override
    {
        return new CircleBlock();  //堆区开辟内存存放积木对象
    }
};

//具体方形积木工厂类
class SquareBlockFactory:public BlockFactory{
public:  
    //重写接口函数
    Block* createBlock() override
    {
        return new SquareBlock();  //堆区开辟内存存放积木对象
    }
};

建立积木工厂系统。该系统根据输入要求去建立相对应的工厂,让该工厂去生产具体产品:

//建立积木工厂系统
class BlockManageSystem{
private:
    //使用Block*动态数组来记录积木信息
    vector<Block *> blocks;
public:
    //根据输入,建立积木生产函数。根据具体产品类型调用相对应的产品工厂
    void produceBlocks(BlockFactory* factory, int num)
    {
        for(int i=0; i<num; i++)
        {
            Block* block = factory->createBlock();
            this->blocks.push_back(block);
            block->produce();
        }
    }
    
    //由于具体积木存放在堆区,所以要使用delete进行内存释放
    ~BlockManageSystem(){
        for(Block* block : blocks)
        {
            delete block;
        }
    }
    
    //获取所有积木。第一个const修饰返回的引用,即使得到积木,也不能对积木进行修改。
    //第二个const修饰this指针,保证this指针不能对积木进行修改
    const vector<Block*> & getBlocks()const{
        return blocks;
    }
    
};

总体代码:

#include<iostream>
#include<vector>
#include<string>
using namespace std;

//按照工厂模式的组成,依次实现抽象产品类、具体产品类、抽象工厂类、具体工厂类

//抽象积木产品类,定义生产具体积木的接口produce()
class Block{
public:
    //写成纯虚函数,一方面将该类变成抽象类,另一方面方便具体产品类实现多态
    virtual void produce() = 0;
};


//具体圆形积木产品类
class CircleBlock: public Block{
public:
    //重写父类虚函数
    void produce() override {
        cout<<"Circle Block"<<endl;
    }
};

//具体方形积木产品类
class SquareBlock: public Block{
public:
    //重写父类虚函数,使用override关键字编译器会检查重写是否正确,不是非要加
    void produce() override
    {
        cout<<"Square Block"<<endl;
    }
};


//抽象工厂类,提供一个抽象的接口用于创建对象。具体哪种对象还得用多态实现
class BlockFactory{
public:
    //抽象的接口。 使用积木的基类指针作为返回值,其可以接收圆形或方形的积木对象(C++多态允许)
    virtual Block* createBlock() = 0;
};

//具体圆形积木工厂类
class CircleBlockFactory:public BlockFactory{
public:  
    //重写接口函数
    Block* createBlock() override
    {
        return new CircleBlock();  //堆区开辟内存存放积木对象
    }
};

//具体方形积木工厂类
class SquareBlockFactory:public BlockFactory{
public:  
    //重写接口函数
    Block* createBlock() override
    {
        return new SquareBlock();  //堆区开辟内存存放积木对象
    }
};


//建立积木工厂系统
class BlockManageSystem{
private:
    //使用Block*动态数组来记录积木信息
    vector<Block *> blocks;
public:
    //根据输入,建立积木生产函数。根据具体产品类型调用相对应的产品工厂
    void produceBlocks(BlockFactory* factory, int num)
    {
        for(int i=0; i<num; i++)
        {
            Block* block = factory->createBlock();
            this->blocks.push_back(block);
            block->produce();
        }
    }
    
    //由于具体积木存放在堆区,所以要使用delete进行内存释放
    ~BlockManageSystem(){
        for(Block* block : blocks)
        {
            delete block;
        }
    }
    
    //获取所有积木。第一个const修饰返回的引用,即使得到积木,也不能对积木进行修改。
    //第二个const修饰this指针,保证this指针不能对积木进行修改
    const vector<Block*> & getBlocks()const{
        return blocks;
    }
    
};

int main()
{
    int produceNum;  //生产次数
    cin>>produceNum;
    
    BlockManageSystem mySystem;  //创建积木工厂系统
    
    
    for(int i=0; i< produceNum; i++)
    {
        string blockType;
        int blockNum;
        //读取生产积木的类型和数量
        cin>>blockType>>blockNum;
        if(blockType == "Circle") 
        {
            //需要使用工厂系统调用圆形积木工厂启动生产
            mySystem.produceBlocks(new CircleBlockFactory(),blockNum);
        }
        else if (blockType == "Square") 
        {
            //需要使用工厂系统调用方形积木工厂启动生产
            mySystem.produceBlocks(new SquareBlockFactory(),blockNum);
        }
    }
    return 0;
}

4.工厂模式应用场景

工厂方法模式使得每个工厂类的职责单一每个工厂只负责创建一种产品,当创建对象涉及一系列复杂的初始化逻辑,而这些逻辑在不同的子类中可能有所不同时,可以使用工厂方法模式将这些初始化逻辑封装在子类的工厂中。

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

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

相关文章

【STL详解 —— priority_queue的使用与模拟实现】

STL详解 —— priority_queue的使用与模拟实现 priority_queue的使用priority_queue的介绍priority_queue的定义方式priority_queue各个接口的使用 priority_queue的模拟实现仿函数priority_queue的模拟实现 priority_queue的使用 priority_queue的介绍 std::priority_queue 是…

基于Echarts的超市销售可视化分析系统(数据+程序+论文

本论文旨在研究Python技术和ECharts可视化技术在超市销售数据分析系统中的应用。本系统通过对超市销售数据进行分析和可视化展示&#xff0c;帮助决策层更好地了解销售情况和趋势&#xff0c;进而做出更有针对性的决策。本系统主要包括数据处理、数据可视化和系统测试三个模块。…

专项1:理论横向误差计算

1.前言 车辆实际位置与轨迹要求的位置的误差大小是反映自动驾驶控制精度的关键性指标&#xff0c;也是作为控制系统的输入量。在对车辆的控制算法进行研究时候&#xff0c;首先需要厘清控制系统的输入。控制系统的输入的关键性环节就是笛卡尔坐标系和frent坐标系之间的转换。 …

【进阶篇】四、字节码增强框架:ASM、ByteBuddy

文章目录 1、ASM2、ASM字节码增强3、ASM入门案例4、ASM Java Agent实现增强类的方法5、Byte Buddy6、Byte Buddy案例 相比自己的代码里用Spring AOP添加某些功能&#xff0c;字节码增强更适配无侵入式的Java Agent场景。比如下面写个Java Agent打印 任意Java程序中方法执行的…

电商技术揭秘九:搜索引擎中的SEO数据分析与效果评估

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台的个性…

DC-3渗透测试复现

DC-3渗透测试复现 目的&#xff1a; 获取最高权限以及5个flag 过程&#xff1a; 信息打点-sql注入-反弹shell- pkexec提权&#xff08;CVE-2021-4034&#xff09; 环境&#xff1a; 攻击机&#xff1a;kali(192.168.85.136) 靶机&#xff1a;DC_3(192.168.85.133) 复现…

记录一下hive跑spark的insert,update语句报类找不到的问题

我hive能正常启动&#xff0c;建表没问题&#xff0c;我建了一个student表&#xff0c;没问题&#xff0c;但执行了下面一条insert语句后报如下错误&#xff1a; hive (default)> insert into table student values(1,abc); Query ID atguigu_20240417184003_f9d459d7-199…

「每日跟读」英语常用句型公式 第13篇

「每日跟读」英语常用句型公式 第13篇 1. How was __? __怎么样&#xff1f; How was the concert last night? &#xff08;昨晚的音乐会怎么样&#xff1f;&#xff09; How was your trip to the museum? &#xff08;你去博物馆的旅行怎么样&#xff1f;&#xff09…

Rust腐蚀服务器修改背景和logo图片操作方法

Rust腐蚀服务器修改背景和logo图片操作方法 大家好我是艾西一个做服务器租用的网络架构师。在我们自己搭建的rust服务器游戏设定以及玩法都是完全按照自己的想法设定的&#xff0c;如果你是一个社区服那么对于进游戏的主页以及Logo肯定会有自己的想法。这个东西可以理解为做一…

嵌入式4-16

tftpd #include <myhead.h> #define SER_IP "192.168.125.243" //服务器IP地址 #define SER_PORT 69 //服务器端口号 #define CLI_IP "192.168.125.244" //客户端IP地址 #define CLI_PORT 8889 //客户端端…

MSQL DML数据操作语言

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

【MogDB】在ORACLE和MogDB中查看存储过程出参游标数据的方式

一、前言 使用ORACLE作为数据库的应用软件中&#xff0c;偶尔会遇到使用游标作为出参的存储过程&#xff0c;这种存储过程迁移到MogDB并不需要进行改造&#xff0c;但是在开发这样的存储过程时&#xff0c;开发人员偶尔会想要在数据库中测试执行一下&#xff0c;看看游标中的数…

Fiddler安装与使用的深度解析

在现今的互联网开发领域&#xff0c;无论是前端开发、后端开发&#xff0c;还是移动应用开发&#xff0c;对HTTP协议的深入理解和应用都至关重要。而在这个过程中&#xff0c;一个强大的HTTP调试代理工具就显得尤为关键。Fiddler&#xff0c;作为一款功能强大的网络调试工具&am…

数据库练习(二)

建表 create table employee(empno int primary key auto_increment , ename char(10) , job char(6) , mgr int , hiredate date , sal float(10,2),comm float(10,2),deptno int ); insert into employee(empno…

【简单介绍下单片机】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

元类的执行

class MetaB(type):def __new__(cls, name, bases, attrs):print(f"使用元类 {cls.__name__} 创建{name}类 ")return super().__new__(cls, name, bases, attrs)class A(metaclassMetaB):passclass C(A):pass元类MetaB的__new__方法应该只会在创建类A时被调用一次, 因…

集成电路测试学习

集成电路&#xff08;Integrated Circuit&#xff0c;IC&#xff09;整个设计流程包括&#xff1a;电路设计、晶圆制造、晶圆测试、IC封装、封装后测试。 IC测试目的&#xff1a;一、确认芯片是否满足产品手册上定义的规范&#xff1b;二、通过测试测量&#xff0c;确认芯片可以…

Python爬虫:requests模块的基本使用

学习目标&#xff1a; 了解 requests模块的介绍掌握 requests的基本使用掌握 response常见的属性掌握 requests.text和content的区别掌握 解决网页的解码问题掌握 requests模块发送带headers的请求掌握 requests模块发送带参数的get请求 1 为什么要重点学习requests模块&…

Unity架构师进阶:红点系统的架构与设计

面试的时候经常被问道如何来设计一个红点系统,本文将详细地介绍如何设计一个红点系统&#xff0c;有哪些接口&#xff0c;并完整地给出实现。 红点系统的需求分析 首先我们来分析一下红点系统的设计需求: 红点系统严格意义上来说不属于框架&#xff0c;而是游戏逻辑&#xff0…

DOS时代经典软件,落下帷幕,国产中文编程,蓬勃发展

互联网的变迁好像翻涌的波涛&#xff0c;有些我们以为已经忘掉的软件&#xff0c;其实还留在我们心里&#xff0c;特别是那些经历过从DOS系统换到Windows系统的人&#xff0c;这种感觉更加明显。 说起DOS软件&#xff0c;它是很多80后年轻时的美好记忆。虽然现在它已经成为了过…