工厂模式的学习笔记,代码案例

适用读者:刚接触工厂模式的学生

项目简介:这里有多个动物,分别是人、猫、狗、鱼等,我在键盘上输入其中一个的名字,然后屏幕列出相应的动物相关信息。

语言: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* 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

执行即可,效果如图所示

工厂模式的学习笔记,代码案例

3.项目心得

错误1:scanf格式错误。

现象:屏幕“一秒五喷”的速度疯狂打印信息,吓我一跳,感觉错的莫名其妙。

分析过程:循环打印,以为是while循环没写好,把指针对象改了改,无效;又调了调buf,无效;然后用gets试了试OK,才意识到格式不对。

结论:使用了 scanf(&xxx) 的样式,可能是gets 用多了,搞得记忆混淆了...

上一篇:[java]多态


下一篇:【Java】万物皆对象——面向对象编程