很多人说C语言是面向过程的编程语言,但其实准确些说,面向过程和面向对象只是一种编程思想,而不是编程语言的种类。C语言只是不太友好的面向对象的编程语言。
概述
实现思想
工厂模式多数情况下都是应用于JAVA中,但是在C中也可以实现。
通过代码编写练习后,感觉就像是一个大厂里边有好多部门,他们有一些共同的特征(结构体),而每一个部门下面又会有好多员工,他们的每一种特征又会有属于自己的属性(结构体创建的实例)。
官方一点的说法就是这样:
- Factory(工厂):核心部分,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象
- Product(抽象类产品):工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象
- ConcreteProduct(具体产品):简单工厂模式的创建目标,所有被创建的对象都是某个具体类的实例。它要实现抽象产品中声明的抽象方法(有关抽象类)
在编写程序的时候要,一人一个文件来编写,用到谁就把谁拿出来。
简单工厂模式的优点
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责
- 客户端无需知道所创建具体产品的类名,只需知道参数即可
- 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。(这也是我在开始的披萨店里遇到没有的披萨的解决情况)
简单工厂模式的缺点
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦异常,整个系统将受影响
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
- 简单工厂模式使用了static工厂方法,造成工厂角色无法形成基于继承的等级结构。
简单工厂模式的适用环境
-
工厂类负责创建对的对象比较少,因为不会造成工厂方法中的业务逻辑过于复杂
-
客户端只知道传入工厂类的参数,对如何创建对象不关心
demo
下面是自己编写的一段demo来模拟一下下智能家居:
主程序main.c
#include "light.h"
#include "tool.h"
int main()
{
char cmd[30];
struct light* phead = NULL;
struct light* tmp = NULL;
phead = put_bedroomLight_in_link(phead);
if(phead != NULL)
printf("%s is already!\n",phead->name);
phead = put_sittingroomLight_in_link(phead);
if(phead != NULL)
printf("%s is already!\n",phead->name);
phead = put_kitchenLight_in_link(phead);
if(phead != NULL)
printf("%s is already!\n",phead->name);
while(1){
tmp = phead;
memset(cmd,0,sizeof(char));
printf("\n---------------------------------------------------------\n\n");
scanf("%s",cmd);
tmp = findByName(phead,cmd);
if(tmp != NULL)
{
tmp->lightOn();
tmp->lightOff();
}
}
}
(部门)light.h:
#ifndef __LIGHT_H__
#define __LIGHT_H__
#include <stdio.h>
struct light* put_bedroomLight_in_link(struct light* phead);
struct light* put_sittingroomLight_in_link(struct light* phead);
struct light* put_kitchenLight_in_link(struct light* phead);
struct light {
char name[30];
int no;
void (*lightOn)();
void (*lightOff)();
struct light* next;
};
#endif
light部门下的员工:
bedroomLight:
#include "light.h"
void bedroom_light_on()
{
printf("bedroom light on!\n");
}
void bedroom_light_off()
{
printf("bedroom light off!\n");
}
struct light bedroom_light = {
.name = "bedroomLight",
.lightOn = bedroom_light_on,
.lightOff = bedroom_light_off,
};
struct light* put_bedroomLight_in_link(struct light* phead)
{
if(phead == NULL)
{
phead = &bedroom_light;
return phead;
}
else
{
bedroom_light.next = phead;
phead = &bedroom_light;
return phead;
}
}
kitchenLight
#include "light.h"
void kitchen_light_on()
{
printf("kitchen light on!\n");
}
void kitchen_light_off()
{
printf("kitchen light off!\n");
}
struct light kitchen_light = {
.name = "kitchenLight",
.lightOn = kitchen_light_on,
.lightOff = kitchen_light_off
};
struct light* put_kitchenLight_in_link(struct light* phead)
{
if(phead == NULL)
{
phead = &kitchen_light;
return phead;
}
else
{
kitchen_light.next = phead;
phead = &kitchen_light;
return phead;
}
}
sittingroomLight
#include "light.h"
void sittingroom_light_on()
{
printf("sittingroom light on!\n");
}
void sittingroom_light_off()
{
printf("sittingroom light off!\n");
}
struct light sittingroom_light = {
.name = "sittingroomLight",
.lightOn = sittingroom_light_on,
.lightOff = sittingroom_light_off
};
struct light* put_sittingroomLight_in_link(struct light* phead)
{
if(phead == NULL)
{
phead = &sittingroom_light;
return phead;
}
else
{
sittingroom_light.next = phead;
phead = &sittingroom_light;
return phead;
}
}
还有我自己写的一个功能函数库
#ifndef __TOOL_H__
#define __TOOL_H__
#include <stdio.h>
#include "light.h"
#include <string.h>
struct light* findByName(struct light* phead,char* str)
{
struct light* temp = phead;
if(temp == NULL)
{
printf("Init is null!\n");
return NULL;
}
else
{
while(temp != NULL)
{
if(strcmp(temp->name,str) == 0)
{
printf("Function is already!\n");
return temp;
}
temp = temp->next;
}
}
}
#endif
运行结果:
总结以下自己在编写这个demo时候遇到的一些问题吧:
- 当时自己在编写库函数的时候没有加#ifndef、#define、#endif,结果报了一些函数没有定义的错误
- 在各个员工初始化自己结构体中(部分)属性的时候,写的成员函数不用放在”部门“的库中,只有那些静态函数(功能函数需要放在”部门“的库中提前声明)
- 因为自己太久不做数据结构的题了,链表在使用的时候,总忘记声明一个临时变量来表示一下头指针
- 在更新新的”员工“的时候,只需要在工程文件中,复制粘贴一份已有的”员工“,直接进行修改代码即可
这样写完的代码,耦合度会比较低,而且易更改,逻辑比较清晰。