什么是工厂模式(C语言面向对象实现)

什么是工厂模式(C语言示例)

絮絮叨叨:今天师傅让我给他讲讲什么是工厂模式,工厂模式又要怎么用。

虽然说知道什么是工厂模式,但是在还没在实际的代码中用过。于是乎又深入的学习了下,发现工厂模式其实我们都见过,只是并没意识到而已。


什么是工厂模式

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

按照我的理解就是:“工厂模式将创建对象和使用对象两个过程分离,对于使用者无需关心对象的产生过程,直接指定需要的对象即可使用该对象的方法

举一个我们生活中实际的例子。

您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。

一个栗子

在某一项目需要用到 EEPROM、Flash 这两个设备,分别保存不同数据。在使用常规写法是下面的代码。

///>> eeprom.c
#include <stdint.h>
#include <stdio.h>
#include <string.h>

void eeprom_init(void)
{
    printf("初始化 EEPROM\n");
}

void eeprom_open(void)
{
    printf("启用 EEPROM\n");
}

void eeprom_write(uint32_t addr, uint8_t *data, uint16_t len)
{
    printf("向EEPROM 地址:%x 写入%d 字节数据:%s\n", addr, len, (char *)data);
}
///>> eeprom.h
void eeprom_init(void);
void eeprom_open(void);
void eeprom_write(uint32_t addr, uint8_t *data, uint16_t len);
///>> flash.c
void flash_init(void)
{
    printf("初始化 FLASH\n");
}

void flash_open(void)
{
    printf("启用 FLASH\n");
}

void flash_write(uint32_t addr, uint8_t *data, uint16_t len)
{
    printf("向FLASH 地址:%x 写入%d 字节数据:%s\n", addr, len, (char *)data);
}
///>> flash.h
void flash_init(void)
void flash_open(void)
void flash_write(uint32_t addr, uint8_t *data, uint16_t len);
///>> main.c
#include "eeprom.h"
#include "flash.h"

int main(void)
{
    char *str[] = {"我是EEPROM", "我是FLASH"};

    eeprom_init();
    eeprom_open();
    flash_init();
    flash_open();
    eeprom_write(0x0100, str[0], strlen(str[0]));
    flash_write(0x02000100, str[1], strlen(str[1]));
}

运行结果为:

初始化 EEPROM
启用 EEPROM
初始化 FLASH
启用 FLASH
向EEPROM 地址:100 写入12 字节数据:我是EEPROM
向FLASH 地址:2000100 写入11 字节数据:我是FLASH

在上面的应用代码中(main函数)直接使用了eeprom和flash相关的API(包含eeprom.h和flash.h),所以main 对eeprom、flash 产生了依赖。

如果后面嫌弃flash容量不够,而换成SD卡,那main 函数和flash相关的的API都需要更改,在频繁更换的场景这是繁琐的。

使用工厂模式

使用工厂模式实现上述功能,代码需要怎么写呢?

工厂模式是使用一个工厂接口将其他类的所有创建初始化处理完成,对于应用程序无需关心创建的细节。

首先创建抽象出一个存储类,保存所有存储类信息到数组,然后创建工厂函数,在工厂函数中查找对应的实例,然后对它进行初始化。

我们保持上面的eeprom.c、flash.c 不变,创建一个factory.c和对应头文件。代码如下:

///>> factory.h
typedef struct storage
{
    char *name;
    void (*init)(void);
    void (*open)(void);
    void (*write)( uint32_t, uint8_t *, uint16_t);
} * storage_t;

storage_t storage_factory(char *name);
///>> factory.c
struct storage storage_list[] =
{
    {"eeprom", eeprom_init, eeprom_open, eeprom_write},
    {"flash", flash_init, flash_open, flash_write},
};

storage_t storage_factory(char *name)
{
    int i;

    for (i = 0; i < sizeof(storage_list) / sizeof(storage_list[0]); i++)
    {
        if (0 == strcmp(name, storage_list[i].name))
        {
            storage_list[i].init();
            storage_list[i].open();
            return &storage_list[i];
        }
    }

    return NULL;
}
///>>main.c
#include "factory.h"

int main(void)
{
    char *str[] = {"我是EEPROM", "我是FLASH"};

    storage_t byte_data = storage_factory("eeprom");
    storage_t sector_data = storage_factory("flash");

    byte_data->write(0x0100, str[0], strlen(str[0]));
    sector_data->write(0x02000100, str[1], strlen(str[1]));
}

在这一份代码中,main 、eeprom 和 flash 之间的耦合解除了,main.c 的依赖变成了factory 。运行结构依旧和上面相同。

而如果需要将flash 换成 sd 卡,则main 函数只需将 工厂创建时传递的名字改成sd,并在factory添加对应的处理操作方法即可。

身边的工厂模式

不知道有人对上面的第二中代码是否感到熟悉,在C语言的文件操作,linux 的设备驱动,都是使用类似的方式初始化并开启设备。

而对于使用者而言,我们并不需要对设备的初始化流程有了解,只需要使用 fopen\open 函数进行打开需要的文件名,其他过程在内部已经将这些完成。

所有从某种角度而言,open\fopen 函数就是一个工厂的入口,它将具体的设备初始化细节进行屏蔽。

后记

在上面的第一种方法,其实属于面向过程编程。

在第二种方法,使用结构体将eeprom和flash抽象成了一个存储类,变成了简单的面向对象编程。

在上面的过程中,依赖关系从main 依赖 eeprom变成了 main 依赖 factory,从而达到解耦的目的。
或者还可以说,eeprom 通过 factory 向 main 中注入了依赖关系,这也就是依赖注入


我开通微信公众啦!
在我的公众号还有很多文章更新哟!排版也更好看😎

CSDN博客:非典型技术宅

github : https://github.com/Gary-Hobson

个人公众号:
在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值