适用读者:刚接触工厂模式的学生
项目简介:这里有多个动物,分别是人、猫、狗、鱼等,我在键盘上输入其中一个的名字,然后屏幕列出相应的动物相关信息。
语言:C
相关知识点:结构体(C语言实现类与对象),链表,分文件编程;
1. 工厂模式的介绍
定义:创建对象的一种最佳模式;
优点:main函数会变得简洁;不会暴露创建逻辑、实现方式;
具体做法:把项目拆分为多个对象,每个对象单独写c文件,相关联系及部分定义放在h文件;
2. 源代码
2.1. 先写一个头文件,用于存储结构体定义,这是所有对象共同用到的。
-
Animal.h
//结构体的定义。作为各个C文件的支持
struct Animal{
char name[128];
int age; //成员属性
char sex[128];
int others;
void (*peat)(); //成员方法
void (*pbeat)();
struct Animal *next; //作为链表
};
//下述函数声明,用于mainpro.c。属于各个C文件
struct Animal* putCatInLink(struct Animal* pHead);
struct Animal* putDogInLink(struct Animal* pHead);
struct Animal* putPersonInLink(struct Animal* pHead);
struct Animal* putFishInLink(struct Animal* pHead);
2.2. 再单独写各个对象的C文件,里边写具体的实现函数,以及给对象赋值。
cat.c
#include "Animal.h" //调用结构体定义
#include <stdio.h>
void catEat()
{
printf("cat eat fish\n");
}
void catBeat()
{
printf("cat fight\n");
}
//创建对象并赋值
struct Animal cat =
{
.name = "Tom",
.peat = catEat,
.pbeat = catBeat
};
//把猫插入链表,用的是头插法;
struct Animal* putCatInLink(struct Animal* pHead)
{
if (pHead == NULL)
{
pHead = &cat;
return pHead;
}
else
{
cat.next = pHead;
pHead = &cat;
return pHead;
}
}
dog.c
#include "Animal.h" //调用结构体定义
#include <stdio.h>
void dogEat()
{
printf("dog eat fish\n");
}
void dogBeat()
{
printf("dog fight\n");
}
//创建对象并赋值
struct Animal dog =
{
.name = "Panghu",
.peat = dogEat,
.pbeat = dogBeat
};
//把猫插入链表,用的是头插法;
struct Animal* putDogInLink(struct Animal* pHead)
{
if (pHead == NULL)
{
pHead = &dog;
return pHead;
}
else
{
dog.next = pHead;
pHead = &dog;
return pHead;
}
}
person.c
#include "Animal.h" //调用结构体定义
#include <stdio.h>
void personEat()
{
printf("person eat fish\n");
}
void personBeat()
{
printf("person fight\n");
}
//创建对象并赋值
struct Animal person =
{
.name = "Kopito",
.peat = personEat,
.pbeat = personBeat
};
//把猫插入链表,用的是头插法;
struct Animal* putPersonInLink(struct Animal* pHead)
{
if (pHead == NULL)
{
pHead = &person;
return pHead;
}
else
{
person.next = pHead;
pHead = &person;
return pHead;
}
}
fish.c
#include "Animal.h" //调用结构体定义
#include <stdio.h>
void fishEat()
{
printf("fish eat fish\n");
}
void fishBeat()
{
printf("fish fight\n");
}
//创建对象并赋值
struct Animal fish =
{
.name = "fisher",
.peat = fishEat,
.pbeat = fishBeat
};
//把猫插入链表,用的是头插法;
struct Animal* putFishInLink(struct Animal* pHead)
{
if (pHead == NULL)
{
pHead = &fish;
return pHead;
}
else
{
fish.next = pHead;
pHead = &fish;
return pHead;
}
}
2.3 主程序,写一个main.c文件,作为代码的入口
main.c
#include "Animal.h"
#include <stdio.h>
#include <string.h>
struct Animal* init_creatLink(struct Animal* pHead);
struct Animal* serchDev(char* bufName, struct Animal* pHead);
int main()
{
// char bufName[128] = {'\0'};
char bufName[128];
// 指针变量
struct Animal* pHead = NULL;
struct Animal* pSomeOne = NULL;
/*初始化_链表:把各个对象串联起来*/
pHead = init_creatLink(pHead);
/*业务逻辑:等待用户输入,并检索后响应*/
while(1)
{
printf("which dev you wanna?\n");
printf("Tom,fisher,Panghu,Kopito\n");
scanf("%s",bufName);
//gets(&bufName);
printf("get name = %s\n",bufName);
/*检索对象:用到strcmp*/
pSomeOne = serchDev(bufName,pHead);
if (pSomeOne != NULL)
{
printf("====================\n");
printf("I am %s\n",pSomeOne->name);
pSomeOne->peat();
pSomeOne->pbeat();
printf("====================\n");
}
//memset(bufName,'\0',sizeof(bufName));
}
return 0;
}
struct Animal* init_creatLink(struct Animal* pHead)
{
pHead = putCatInLink(pHead);
pHead = putDogInLink(pHead);
pHead = putPersonInLink(pHead);
pHead = putFishInLink(pHead);
return pHead;
}
struct Animal* serchDev(char* bufName, struct Animal* pHead)
{
if (pHead == NULL)
{
printf("empty linked list\n");
return NULL;
}
else
{
while (pHead!= NULL)
{
if(strcmp(bufName,(pHead->name)) == 0)
{
return pHead;
}
pHead = pHead->next;
}
printf("warning: name not find!\n\n");
printf("======================\n\n");
return NULL;
}
}
2.4 编译与执行
gcc *.c -o xxx
把所有文件放在一个路径,共同编译。
星号*指的是所有c文件。
随意一个执行文件名
./xxx
执行即可,效果如图所示
3.项目心得
错误1:scanf格式错误。
现象:屏幕“一秒五喷”的速度疯狂打印信息,吓我一跳,感觉错的莫名其妙。
分析过程:循环打印,以为是while循环没写好,把指针对象改了改,无效;又调了调buf,无效;然后用gets试了试OK,才意识到格式不对。
结论:使用了 scanf(&xxx) 的样式,可能是gets 用多了,搞得记忆混淆了...