C 语言实现简单工厂模式

news2024/11/19 1:31:59

文章目录

    • 1. 背景介绍
    • 2. 设计实现
    • 3. 运行测试
    • 4. 总结

1. 背景介绍

印象中,设计模式是由面向对象的语言(C++、JAVA)才能完成的,而 C 语言是面向过程的语言,不能实现设计模式。但C 语言中有 函数指针回调函数 等机制,使用这些机制便能写出面向对象的优秀程序。

LINUX 操作系统,采用 C 语言写的,但是里面很多模块实现都是通过面向对象的设计方式实现的,这也是很多人初看 Linux 源码看得云里雾里的原因。

面向过程(Procedure Oriented 简称 PO): 把事情拆分成几个步骤(相当于拆分成一个个的方法和数据),然后按照一定的顺序执行。

面向对象(Object Oriented 简称 OO): 面向对象会把事物抽象成对象的概念,先抽象出对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法。

2. 设计实现

在 C++中实现设计模式主要是通过virtual 关键字修饰的虚函数来实现的,在 C 语言中没有这个操作,但是可以通过指针函数加结构体进行实现。先简单了解一下指针函数:

typedef void (*pfunc)(int); //此处定义了pfunc这个函数指针

//定义一个test_func函数,与pfunc的返回类型和参数是一致的,只有名字不同
//若不一致则不能定义pfunc的指针指向test_func
void test_func(int id)      
{   
    printf("id=%d \n", id);
}

//使用func指向test_func()
pfunc func = test_func;

//调用func(id) 与 test_func(id)实现的功能一致
func(1);//即可使用

//与结构体结合
typedef struct func_t
{
    void (*func)(int id);
}func_t;

func_t f;
f.func = test_func; //结构体的函数指针指向test_func()
f.func(1); //调用结构体的函数指针,与调用test_func(1)效果一致

//通过上述例子,可以看到通过结构体+函数指针可以实现封装信息并指向另外一个函数
//有了这个特性可以实现一个简单工厂模式

本设计实现一个简单的工厂模式,一个生产不同种类水果的工厂。每种水果有两个属性show() eat(),实现 apple、banana、pear 这 3 种水果。

//设计抽象定义接口
//定义的抽象的水果接口
typedef struct Ifruit_t
{
    void (*show)(void* obj);  //显示信息
    void (*eat)(void* obj);   //怎么eat
    void *obj;                //指向当前的结构体
}Ifruit_t;

下面程序是香蕉水果相关的定义, 另外的苹果与梨定义与这个几乎完全一致,此处考虑篇幅问题,不全部贴出来了。

//------------------------------------------------
//实现香蕉相关的定义
//------------------------------------------------
typedef struct banana_t             //与Ifruit_t的定义一致
{
    void (*show)(void* obj);        //显示信息
    void (*eat)(void* obj);         //怎么eat
    void *obj;                      //指向当前的结构体
}banana_t;

static void banana_show(void* obj)   //使用static修饰,避免被外部直接调用
{
    printf("我是香蕉!\n");
}

static void banana_eat(void* obj)  //使用static修饰,避免被外部直接调用
{
    printf("操作: 先剥掉皮,再吃!\n");
}
//香蕉的构造函数
banana_t* constructor_banana(void)  //不使用static修饰,让外部直接调用
{
    banana_t* obj = (banana_t*)malloc(sizeof(banana_t));
    obj->show = banana_show;        //给指针函数赋值,后面才能被调用
    obj->eat = banana_eat;          //给指针函数赋值,后面才能被调用
    obj->obj = obj;                 //obj指向当前结构体指针
    return obj;
}

工厂实现的函数如下:

enum FruitType  //枚举类型
{
    APPLE,      //苹果
    BANANA,     //香蕉
    PEAR,       //梨
};

Ifruit_t* factor_create_fruit(enum FruitType type) //工厂:生成水果的
{
    Ifruit_t *fruit=NULL;

    switch (type)
    {
    case APPLE:
        fruit = (Ifruit_t *)constructor_apple();
        printf("工厂: 生产苹果!\n");
        break;
    case BANANA:
        fruit = (Ifruit_t *)constructor_banana();
        printf("工厂: 生产香蕉!\n");
        break;
    case PEAR:
        fruit = (Ifruit_t *)constructor_pear();
        printf("工厂: 生产梨!\n");
        break;
    default:
        break;
    }
    return fruit;
}

main 使用流程如下。工厂设计模式它的优势是易于扩展,此处实现了香蕉、苹果、梨种水果,当业务中需要西瓜时,写一个西瓜相关的结构体并实现对应函数,实现方式和上面 banana 实现方式一致,而对于西瓜的使用依旧是如下调用fruit->show(NULL); fruit->eat(NULL);,这样主体的业务逻辑便能完成以较小的改动来添加一个新的模块功能。

int main(void)
{
    Ifruit_t *fruit=NULL;

    fruit = factor_create_fruit(APPLE); //生成苹果
    //每一次有新的水果添加进来,步骤都和下面一样的,易于扩展
    fruit->show(NULL);                  //显示苹果
    fruit->eat(NULL);                   //操作苹果
    free(fruit);                        //不使用了,释放资源
    printf("\n");

    fruit = factor_create_fruit(BANANA);
    fruit->show(NULL);
    fruit->eat(NULL);
    free(fruit);
    printf("\n");

    
    fruit = factor_create_fruit(PEAR);
    fruit->show(NULL);
    fruit->eat(NULL);
    free(fruit);

    return 0;
}

3. 运行测试

运行结果:

在这里插入图片描述

4. 总结

虽然C语言是面向过程的编程语言,但是在设计程序的时候,可以考虑用面向对象的方式去设计,这样提高程序的“高内聚、低耦合”特性,便于维护。

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

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

相关文章

Java中线程的生命周期

Java中线程的生命周期 Java中线程的声明周期与os中线程的生命周期不太一样,java中线程有6个状态,见下: NEW: 初始状态,线程被创建出来但没有被调用 start() 。RUNNABLE: 运行状态,线程被调用了 start()等待运行的状态…

Elasticsearch:使用 Redis 让 Elasticsearch 更快

Elasticsearch 是一个强大的搜索引擎,可让你快速轻松地搜索大量数据。但是,随着数据量的增长,响应时间可能会变慢,尤其是对于复杂的查询。在本文中,我们将探讨如何使用 Redis 来加快 Elasticsearch 搜索响应时间。 Re…

【数据结构】常见排序算法——常见排序介绍、归并排序、各大排序复杂度和稳定性

文章目录 1.常见排序2.归并排序2.1归并排序基本思想2.2归并排序的实现2.3归并排序特性总结 3.各大排序复杂度和稳定性 1.常见排序 2.归并排序 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andCon…

商业图表工具推荐,热门商业图表工具有哪些?

在如今的商业环境下,数据分析和可视化是非常重要的一环。不仅可以帮助企业更好地了解自身情况,还能为决策提供有力支持。因此,选择一个好用的商业图表工具对于报表开发人员来说是非常重要的。下面将为大家介绍7款热门商业图表工具&#xff0c…

Mac电脑删除第三方软件工具CleanMyMac X

经常使用Mac的人都知道,Mac除了可以在AppStore下载应用程序,还有许多软件是需要在网页上搜索下载的第三方软件。那么这类第三方软件软件除了下载方式不同之外还有什么是和从App store下载的软件有区别的吗?答案是肯定的,那就是这些…

Docker容器进入的4种方式

Docker容器进入的4种方式 Docker容器进入的4种方式 在使用Docker创建了容器之后,大家比较关心的就是如何进入该容器了,其实进入Docker容器有好几多种方式,这里我们就讲一下常用的几种进入Docker容器的方法。 进入Docker容器比较常见的几种…

带你了解自动化测试只需要一分钟

目前自动化测试并不属于新鲜的事物,或者说自动化测试的各种方法论已经层出不穷,但是,能够明白自动化测试并很好落地实施的团队还不是非常多,我们接来下用通俗的方式来介绍自动化测试…… 首先我们从招聘岗位需求说起。看近期的职业…

软件测试什么样的技术才能拿20K薪资?

年少不懂面试经,读懂已是测试人。 大家好,我叫木江,一名历经沧桑,看透互联网行业百态的测试从业者,经过数年的勤学苦练,精钻深研究,终于从初出茅庐的职场新手成长为现在的测试老鸟,早…

MySQL数据库基础 09

第九章 子查询 1. 需求分析与问题解决1.1 实际问题1.2 子查询的基本使用1.3 子查询的分类 2. 单行子查询2.1 单行比较操作符2.2 代码示例2.3 HAVING 中的子查询2.4 CASE中的子查询2.5 子查询中的空值问题2.5 非法使用子查询 3. 多行子查询3.1 多行比较操作符3.2 代码示例3.3 空…

深入浅出对话系统——自然语言理解模块

自然语言理解 首先回顾一下自然语言理解的概念。 自然语言理解(Natural Language Understanding)包含三个子模块: 其中领域识别和意图识别都是分类问题,而语义槽填充属于序列标注问题。所以,在自然语言理解中,我们要解决两个分类…

阿里云(Linux)安装Docker教程

首先安装docker,需要找到帮助文档,那肯定是我们的官网: Install Docker Engine on CentOS | Docker Documentation 找到对应的位置,这里是安装在CentOS中,版本需要Ce…

2021~2022 学年第二学期《信息安全》考试试题(A 卷)

北京信息科技大学 2021~2022 学年第二学期《信息安全》考试试题(A 卷) 课程所在学院:计算机学院 适用专业班级:计科1901-06,重修 考试形式:(闭卷) 一、选择题(本题满分10分,共含10道小题,每小题…

Jenkins结合gitee自动化部署SpringBoot项目

安装 安装教程 插件选择 Gitee Plugin 配置 源码管理 填写源码地址 注意:请确保genkins所在的服务器有权限git拉取远程仓库代码,如果不可以请参考ssh配置centos 配置ssh拉取远程git代码 源码管理 构建触发器 1.勾选Gitee webhook 触发构建 2.生成we…

Python3实现基于ARIMA模型来预测茅台股票价格趋势

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

实验篇(7.2) 10. 扩充物理实验环境 ❀ 远程访问

【简介】本着先简后难原则,我们前面所做的实验,均为客户端远程访问防火墙,现在我们需要实现防火墙和防火墙之间的访问。在现有的实验环境中,加再入一台防火墙。让我们看看需要怎样操作。 网络拓扑 企业之间最常见的远程互相访问&a…

SSM框架编程技术期末复习内容

考试题型:简答题编程题 SSM框架编程技术期末复习 一、代码干货Mybatis实现查询用户表记录数Mybatis根据用户名对用户表进行模糊查询Mybatis使用resultMap实现用户信息查询(用户表和角色表查询)Mybatis根据用户角色id获取用户列表Mybatis获取指定用户的相关信息及其…

【Mircosft Edge】插件推荐

插件推荐 1.推荐插件1.1 油猴 tempermonkey1.2 免费音乐播放器 Listen 1 2.添加插件2.1 打开“Micrsoft Edge 外接程序”2.2 获取新的扩展2.3 搜索插件2.3.1 在Micrsoft Edge 外接程序搜索框中输入tampermonkey,然后点击获取按钮进行安装2.3.2 在Micrsoft Edge 外接…

Misc(2)

第N种方法解决 拿到题目后是一个exe文件,运行不了 为啥非要整个exe,看着都害怕 改后缀后打开发现是base64编码的图片 利用工具解码转png格式 Base64解码 Base64编码 UTF8 GB2312 UTF16 GBK 二进制 十六进制 解密 - The X 在线工具 (the-x.cn) 下载下来的…

MySQL:主从HASH SCAN算法可能导致从库数据错误

本文主要以hash scan全表为基础进行分析,而不涉及到hash scan索引,实际上都会遇到这个问题。本文主要描述的是update event,delete event也是一样的,测试包含8022,8026,8028均包含这个问题。 约定&#xff…

myBatis-plus之CRUD

文章目录 查询普通查询根据 ID 查询根据ID批量查询根据MAP查询 条件构造器查询构造器声明:QueryWrapper方法常用方法,以及简单使用方式实体作为条件构造器构造方法的参数lambda条件构造器 更新普通更新根据 ID 修改 条件构造器更新 删除普通删除根据 ID …