1, 介绍

原型模式是一种比较简单的创建型模式。通过复制的方式,而不是类的实例化,创建一个新对象,新对象跟原型对象具有同样的数据,可以简单的理解为对原型对象的复制。这就类似于我们去打印店打印资料,为了节省成本,第一份资料是打印出来的,后面的几份就是直接复印第一份资料得到的(复印的成本比打印低)。

在什么时候需要原型模式呢?总结下来主要如下场景:

怎么用C语言来实现原型模式呢?下面的第2节会通过一个例子来说明。例子仅作C语言实现原型模式的参考,在实际的情况中可以根据具体情况来使用原型模式,比如重新创建或初始化对象消耗的资源比较多,就可以采用原型模式。其实,在linux中有很多地方运用到原型模式,比如进程的创建。创建的子进程基本上是对父进程的拷贝,刚创建出的子进程跟父进程的页表、信号处理、工作目录等都是一样的。在子进程运行的过程中原型模式,或者做特定的设置子进程才会跟父进程的内容不一样。

原型模式也有优缺点,我们要酌情使用。具体的优缺点如下:

原型模式优点:

原型模式缺点:

2, 举例

#include
#include
#include


typedef struct person {
//define data
char name[32];
int age;
char sex;
//define clone function point
struct person* (*clone)(void *obj);
//define set function point
void (*set)(void *obj, const char *str, int age, char sex);
//define show function point
void (*show)(void *obj);
} person_t;

static void person_set(void *obj, const char *str, int age, char sex)
{
if (!obj || !str)
return;

person_t *p = (person_t *)obj;
strcpy(p->name, str);
p->age = age;
p->sex = sex;
}

static void person_show(void *obj)
{
person_t *p = (person_t *)obj;
printf("name: %s, age: %d, sex: %cn", p->name, p->age, p->sex);
}

static person_t* person_clone(void *obj)
{
person_t *pobj = (person_t *)malloc(sizeof(person_t));
person_t *p = (person_t *)obj;
if (!pobj)
return NULL;

pobj->clone = person_clone;
pobj->set = person_set;
pobj->show = person_show;
strcpy(pobj->name, p->name);
pobj->age = p->age;
pobj->sex = p->sex;

return pobj;
}

person_t* constructor_person(void)
{
person_t* p = (person_t *)malloc(sizeof(person_t));

p->clone = person_clone;
p->set = person_set;
p->show = person_show;

return p;
}

int main(void)
{
//constructor person
person_t *p = constructor_person();
printf("constructor person:n");
p->set(p, "lilei", 14, 'm');
p->show(p);

person_t *p1 = p->clone(p);
printf("clone person:n");
p1->show(p1);

printf("set person:n");
p1->set(p1, "lucy", 15, 'w');
p1->show(p1);

free(p);
free(p1);

return 0;
}

先用构造一个对象,然后通过打印显示出对象的内容。接着调用的clone函数复制一个新的对象p1(这便是原型模式的使用),通过打印p1对象,可以发现是对对象的完整复制。然后再调用p1的set函数,重新赋值其中的name/age/sex,然后再打印出p1对象里的内容,发现已经是修改后的内容。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注