适用读者:刚接触工厂模式的学生
项目简介:这里有多个动物,分别是人、猫、狗、鱼等,我在键盘上输入其中一个的名字,然后屏幕列出相应的动物相关信息。
语言:C
相关知识点:结构体(C语言实现类与对象),链表,分文件编程;
定义:创建对象的一种最佳模式;
优点:main函数会变得简洁;不会暴露创建逻辑、实现方式;
具体做法:把项目拆分为多个对象,每个对象单独写c文件,相关联系及部分定义放在h文件;
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* serchDev(char* bufName, struct Animal* pHead); int main() { //char bufName[128] = {'\0'}; char bufName[128]; struct Animal* pHead = NULL; struct Animal* pSomeOne = NULL; /*把各个对象插入链表*/ pHead = putCatInLink(pHead); pHead = putDogInLink(pHead); pHead = putPersonInLink(pHead); pHead = putFishInLink(pHead); /*用户指定某个对象来使用;循环给命令*/ while(1) { printf("which dev you wanna?\n"); printf("Tom,fisher,Panghu,Kopito\n"); scanf("%s",bufName); //注意:char型的数组,无需取地址符号(&) //gets(&bufName); printf("get name = %s\n",bufName); 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)); } // /*方案二:遍历所有链表并打印*/ // while (pHead != NULL) // { // printf("====================\n"); // // printf("I am %s\n",pHead->name); // printf("age = %d\n",pHead->age); // printf("sex = %s\n",pHead->sex); // // pHead->peat(); // pHead->pbeat(); // // printf("====================\n"); // // pHead = pHead->next; // } return 0; } 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"); return NULL; } }
2.4 编译与执行
gcc *.c -o xxx
把所有文件放在一个路径,共同编译。
星号*指的是所有c文件。
随意一个执行文件名
./xxx
执行即可,效果如图所示
错误1:scanf格式错误。
现象:屏幕“一秒五喷”的速度疯狂打印信息,吓我一跳,感觉错的莫名其妙。
分析过程:循环打印,以为是while循环没写好,把指针对象改了改,无效;又调了调buf,无效;然后用gets试了试OK,才意识到格式不对。
结论:使用了 scanf(&xxx) 的样式,可能是gets 用多了,搞得记忆混淆了...