/ 一、介绍 /
1.原型模式 prototype,是一种 创建型模式 ,它采用复制原型对象的方法来创建对象的实例,具有与原型一样的数据。
2.原型对象自身创建一个目标对象,通过 prototype 模式创建的对象与原始对象具有相同的数值。即拷贝原始对象的数据。
3.主要解决的是:"某些结构复杂的对象"的创建工作,由于需求的变化,但是他们都拥有比较稳定统一的接口。一个复杂对象,具有自我复制的功能,统一一套接口。例如:资源优化场景,一个模块(对象)的初始化需要消耗很大资源,这个资源包括数据、硬件等资源等,然后我们通过拷贝并修改特定的数据来减少重复初始化对象所消耗的资源与时间。
/ 二、设计与实现 /
1.设计思路
设计一个抽象接口结构体(struct Interface_t),包含一些统一接口,然后设计一个 student 结构体,实现抽象结构体定义的接口。注:结构体与函数指针的结合定义对象的使用见上一篇。用 C 语言实现简单工厂模式!
2.接口定义
//定义抽象接口结构体
typedef struct Interface_t
{
//clone()函数指针
struct Interface_t*(*clone)(void *obj);
//设置数据的set()的函数指针
void (*set)(void* obj, const char* name, int age);
//显示信息show()的函数指针
void (*show)(void* obj);
//定义的数据
char name[32];
int age;
}Interface_t;
3. 实现 student 结构体的定义
//定义student结构体,与抽象结构体接口一致
typedef struct Student_t
{
//定义clone函数指针
struct Interface_t*(*clone)(void *obj);
//定义set函数指针
void (*set)(void* obj, const char* str, int age);
//定义show函数指针
void (*show)(void* obj);
//定义数据
char name[32];
int age;
}Student_t;
/**
* 简介: set函数的具体实现,修改数据的
* 参数: obj传入当前student结构体,str即要修改的名字,age即修改的年龄
* 返回值: 无
* 其他:使用static修饰,避免被外部直接调用,但可以通过结构体指针进行调用。
*/
static void student_set(void* obj, const char* str, int age)
{
if(!obj || !str) return;
Student_t* s = (Student_t*)obj;
strcpy(s->name, str); //修改student名字
s->age = age; //修改student年龄
/**
* 简介: 显示student信息
*/
static void student_show(void *obj)
{
Student_t *s = (Student_t*)obj;
printf("显示 学生信息: 姓名[%s] 年龄[%d]\n", s->name, s->age);
}
/**
* 简介: 重要,克隆student对象的数据信息
* 参数: obj即传入当前的student结构体信息
* 返回值:返回克隆的Interface,其已具有student的信息。
* 其他:具有与student相同的数据与接口。
*/
static Interface_t* student_clone(void *obj)
{
Interface_t *iobj = (Interface_t*)malloc(sizeof(Interface_t));
Student_t* s = (Student_t*)obj;
if(!iobj) return NULL;
iobj->show = student_show;
iobj->set = student_set;
iobj->clone = student_clone;
strcpy(iobj->name, s->name);
iobj->age = s->age;
printf("调用clone()函数, clone Student\n");
return iobj;
}
/**
* 简介: student的构造函数,创建一个student对象
* 参数:无
* 返回值:student对象
* 其他:外部调用该函数构造一个student对象
*/
Student_t* constructor_student(void)
{
Student_t* s = (Student_t*)malloc(sizeof(Student_t));
s->clone = student_clone;
s->set = student_set;
s->show = student_show;
return s;
}
/ 三、测试 /
1.测试思路先使用构造函数创建一个 student 对象,调用 set()函数设置值并打印信息。然后使用 student 的 clone()函数克隆一个相同数据的对象赋值给 Interface 统一接口,直接打印信息,此时打印的信息与原始对象即 student 的信息一样的,因为其是克隆来的。最后调用 Interface 的 set 函数修改数据,再次打印显示。
2.测试程序
int main(void)
{
printf("原始的学生信息: \n");
Student_t *s1 = constructor_student();
s1->set(s1, "张三", 32);
s1->show(s1);
printf("\n");
Interface_t* i1 = s1->clone(s1);
free(s1);
printf("调用clone(),拷贝后的信息: \n");
i1->show(i1);
printf("\n");
printf("重新修改信息: ");
i1->set(i1, "李四", 41);
i1->show(i1);
free(i1);
return 0;
}
3.测试结果与预期一致。
/ 四、总结 /
虽然C语言是面向过程的编程语言,但是我们在设计程序的时候,可以考虑用面向对象的方式去设计,这样提高我们程序的“高内聚、低耦合”特性,便于维护。
想要整个工程文件的小伙伴:在微信公众号【Linux编程用C】后台回复 designer 即可获取,不断更新中!
我是小C,欢迎大家关注、点赞支持,我们一起交流讨论学习!
PS:若大家想看C语言版本的其他设计模式,
请大家 点赞! 转发!关注吧!~~