【设计模式】 工厂模式介绍及C代码实现
【设计模式】 工厂模式介绍及C代码实现
背景
在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?
定义
工厂模式是一种创建型设计模式,它提供一种通用的接口来创建对象,但是让子类决定实例化哪个类。工厂模式将对象的创建过程封装在一个工厂类中,避免直接调用构造函数,提高代码的灵活性和可维护性。工厂模式实现了依赖倒置原则,即面向接口编程而不是面向实现编程。
在工厂模式中,有一个抽象工厂接口,定义了工厂类应该实现的方法,以及一组产品接口,定义了工厂类应该创建的产品的通用行为。具体的工厂类实现了抽象工厂接口,用于创建具体的产品对象。
工厂模式可以分为三种不同的类型:简单工厂模式、工厂方法模式和抽象工厂模式。简单工厂模式只有一个工厂类,它根据传入的参数来决定创建哪种类型的产品对象。工厂方法模式定义一个抽象工厂接口和一组产品接口,每个具体的工厂类实现了抽象工厂接口,并创建了一组具体的产品对象。抽象工厂模式定义一组抽象工厂接口和一组抽象产品接口,每个具体的工厂类实现了一组抽象工厂接口,每个具体的产品类实现了一组抽象产品接口。
应用场景
工厂模式适用于以下场景:
- 需要创建复杂对象的场景,可以使用工厂模式将对象的创建过程封装起来,避免直接调用构造函数;
- 需要提供统一的接口来创建一组相关对象的场景,可以使用工厂模式将相关对象的创建过程统一起来;
- 需要避免使用 new 关键字来创建对象的场景,可以使用工厂模式来代替直接调用构造函数。
总的来说,工厂模式是一种非常常用的设计模式,可以提高代码的可维护性、灵活性和可扩展性,因此在各种编程语言中都得到了广泛的应用。
模式结构

实现步骤
工厂模式的实现步骤如下:
-
定义一个抽象产品接口,用于定义一组产品的通用行为。
-
定义一个具体产品类,实现抽象产品接口,用于提供具体的产品实现。
-
定义一个抽象工厂接口,用于定义工厂类应该实现的方法。
-
定义一个具体工厂类,实现抽象工厂接口,用于创建具体的产品对象。
-
在客户端代码中使用工厂类创建具体的产品对象。
C语言代码示例
下面是一个简单的 C 语言工厂模式的示例代码,用于创建不同类型的车辆对象:
#include <stdio.h>
#include <stdlib.h>typedef enum {SEDAN,SUV,HATCHBACK
} CarType;typedef struct {int price;char* model;
} Car;Car* createCar(CarType type) {Car* car = (Car*) malloc(sizeof(Car));if (car == NULL) {return NULL;}switch (type) {case SEDAN:car->price = 20000;car->model = "Sedan Car";break;case SUV:car->price = 30000;car->model = "SUV Car";break;case HATCHBACK:car->price = 15000;car->model = "Hatchback Car";break;default:printf("Invalid car type.\n");free(car);return NULL;}return car;
}int main() {Car* sedan = createCar(SEDAN);printf("Price of %s is %d.\n", sedan->model, sedan->price);free(sedan);Car* suv = createCar(SUV);printf("Price of %s is %d.\n", suv->model, suv->price);free(suv);Car* hatchback = createCar(HATCHBACK);printf("Price of %s is %d.\n", hatchback->model, hatchback->price);free(hatchback);Car* invalid = createCar(100);if (invalid == NULL) {printf("Failed to create invalid car.\n");}return 0;
}
在上面的示例代码中,我们定义了一个 Car 结构体表示车辆,包含价格和型号两个属性,以及一个 CarType 枚举类型表示不同类型的车辆。
createCar 函数是工厂函数,接受一个 CarType 参数,根据不同的类型创建不同的车辆对象,并返回指向 Car 结构体的指针。在 main 函数中,我们调用 createCar 函数创建不同类型的车辆对象,并输出其价格和型号。注意,当传入无效的 CarType 参数时,createCar 函数会返回 NULL。最后,我们需要手动释放 createCar 函数中使用 malloc 函数动态分配的内存。
总结
使用工厂模式可以提高代码的可维护性和可扩展性。当需要新增产品时,只需要增加相应的产品类和工厂类,而无需修改客户端代码。当需要替换产品实现时,只需要修改相应的产品类和工厂类即可,而无需修改客户端代码。
- 工厂设计模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
- 工厂设计模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
- 工厂设计模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
需要注意的是,过度使用工厂模式会增加代码的复杂性和额外的开销。因此,在实际使用时应该根据具体情况进行选择,选择最适合的实现方式。
相关文章:
【设计模式】 工厂模式介绍及C代码实现
【设计模式】 工厂模式介绍及C代码实现 背景 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来…...
深入浅出PaddlePaddle函数——paddle.arange
分类目录:《深入浅出PaddlePaddle函数》总目录 相关文章: 深入浅出TensorFlow2函数——tf.range 深入浅出Pytorch函数——torch.arange 深入浅出PaddlePaddle函数——paddle.arange 语法 paddle.arange(start0, endNone, step1, dtypeNone, nameNone…...
X86 ATT常用寄存器及其操作指令
X86 AT&T常用寄存器及其操作指令 常用寄存器 esp寄存器:当我们需要访问堆栈帧中的变量时,可以使用esp寄存器来获取堆栈帧的基址,以便能够正确地访问堆栈帧中的变量。ebp寄存器:当我们需要调用一个函数时,可以使用…...
Kotlin 高端玩法之DSL
如何在 kotlin 优雅的封装匿名内部类(DSL、高阶函数)匿名内部类在 Java 中是经常用到的一个特性,例如在 Android 开发中的各种 Listener,使用时也很简单,比如://lambda button.setOnClickListener(v -> …...
理光M2701复印机载体初始化方法
理光M2701基本参数: 产品类型:数码复合机 颜色类型:黑白 复印速度:单面:27cpm 双面:16cpm 涵盖功能:复印、打印、扫描 网络功能:支持无线、有线网络打印 接口类型:USB2.0…...
2.25Maven的安装与配置
一.Mavenmaven是一个Java世界中,非常知名的"工程管理工具"/构建工具"核心功能:1.管理依赖在进行一个A 操作之前,要先进行一个B操作.依赖有的时候是很复杂的,而且是嵌套的2.构建/编译(也是在调用jdk)3. 打包把java代码给构建成jar或者warjar就是一个特殊的压缩包…...
《英雄编程体验课》第 12 课 | 递归
文章目录 零、写在前面一、搜索算法的原理二、深度优先搜索三、基于DFS的记忆化搜索四、基于DFS的剪枝五、基于DFS的A*(迭代加深,IDA*)零、写在前面 该章节节选自 《夜深人静写算法》,主要讲解最基础的搜索算法,其中用到的思想就是递归,当然,如果已经对本套体验课了如指…...
35测试不如狗?是你自己技术不够的怨怼罢了
一、做软件测试怎么样? 引用著名软件测试专家、清华大学郑人杰教授的说法:软件测试工程师是一个越老越吃香的职业。 其中就表达了软件测试工作相对稳定、对年龄没有限制、而且随着项目经验的不断增长和对行业背景的深入了解,会越老越吃香。…...
【代码训练营】day42 | 1049. 最后一块石头的重量 II 494. 目标和 474.一和零
所用代码 java 最后一块石头的重量II LeetCode 1049 题目链接:最后一块石头的重量II LeetCode 1049 - 中等 思路 无。 把石头分成重量总和近似两堆,然后两堆石头相撞,剩下的就是最小的石头。每个石头只能用一次,01背包…...
Golang协程常见面试题
协程面试题交替打印奇数和偶数N个协程打印1到maxVal交替打印字符和数字交替打印字符串三个协程打印ABCChannel练习交替打印奇数和偶数 下面让我们一起来看看golang当中常见的算法面试题 使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出. 方法一&…...
种群多样性:智能优化算法求解基准测试函数F1-F23种群动态变化图(视频)
智能优化算法求解基准测试函数F1种群动态变化图智能优化算法求解基准测试函数F2种群动态变化图智能优化算法求解基准测试函数F3种群动态变化图智能优化算法求解基准测试函数F4种群动态变化图智能优化算法求解基准测试函数F5种群动态变化图智能优化算法求解基准测试函数F6种群动…...
Qt 中的XML
XML的基本介绍: 在前端开发中:HTML是用来显示数据,而XML是用来传输和存储数据的 XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种标记语言,很类似 HTMLXML 的设计宗旨是传输数据,而…...
网络应用之URL
URL学习目标能够知道URL的组成部分1. URL的概念URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。2. URL的组成URL的样子:https://news.163.com/18/1122/10/E178J2O4000189FH.html…...
【Linux】重定向原理dup2缓冲区
文章目录重定向原理输出重定向关于FILE解释输出重定向原理追加重定向输入重定向dup2缓冲区语言级别的缓冲区内核缓冲区重定向原理 重定向的本质就是修改文件描述符下标对应的struct file*的内容 输出重定向 输出重定向就是把本来应该输出到显示器的数据重定向输出到另一个文…...
ROG配置ubuntu20.04.5双系统要点
win11ubuntu20.04.5 1. BIOS设置 开机长按F2进入bios设置,修改advanced参数: boot -> 关闭fast bootsecurity -> 关闭secure boot设置VMD controller为Disabled(其他电脑是修改硬盘的SATA和ACHI模式)。但是改了之后windo…...
机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?
机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?最近有用户使用的机械革命旷世G16电脑一开机之后,电脑屏幕就变成了绿色的,无法进行任何的操作。出现这个问题可能是因为电脑中病毒了,或者是系统出现故障。我们可以通过U盘来重新…...
python中关于time模块的讲解---指定格式时间字符串转为时间戳
本文章可以解决任意字符串格式时间转为时间戳 返回json格式 可以在此基础上进行修改 时间格式控制符 说明 %Y 四位数的年份,取值范围为0001~9999,如1900 %m 月份(01~12),例如10 %d 月中的一天(01~31)例…...
MySql存储引擎与索引
MySql引擎 存储引擎是具体操作数据的地方,是一种对数据存储的技术与其配套的功能 不同存储引擎所采用存储的方式的不同,并且索引技巧与锁定水平也不同 根据业务的需求灵活的选择存储引擎即可满足的实际的需要 Innodb Innodb是MySql中的默认安装的引擎…...
typing库
typing 库 引入 在日常代码编写中,由于python语言特性,不用像go等编译性语言一样,在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问,这一特性&#…...
linux shell 入门学习笔记10内置shell命令
bash基础的内置命令 echoevalexecexportreadshift echo命令 -n 不换行输出 -e 解析字符串中的特殊符号\n 换行 \r 回车 \t 制表符 四个空格 \b 退格-n参数演示 xiao123xiao123:~/Downloads$ echo 你真胖;echo 你还挺可爱; 你真胖 你还挺可爱 xiao123xiao123:~/Downloads$ ec…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
Tauri2学习笔记
教程地址:https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引:https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多,我按照Tauri1的教程来学习&…...
