C言語でGoFのPrototypeパターンを実装します。
Prototypeパターンを確認する
まずはPrototypeパターンを確認しましょう。TECHSCOREさんのPrototypeパターンの解説記事をご参照ください。
https://www.techscore.com/tech/DesignPattern/Prototype.html/
Prototypeパターンで設計する
TECHSCOREさんのサンプルコードをC言語に移植します。クラス図は下記のようになります。

Prototypeパターンで実装する
Cloneableを作る
まずはPrototypeパターンの肝であるCloneableを作りましょう。createClone()で何を返すか決められないので*voidを返すようにしておきます。
Cloneable.h
typedef struct Cloneable {
void *(*createClone)(struct Cloneable *c);
} Cloneable;
extern void *Cloneable_createClone(Cloneable *c);
Cloneable.c
void *Cloneable_createClone(Cloneable *c) {
return (void*)c->createClone(c);
}
Paperを作る
CloneableをimpementsするPaperを作りましょう。今回は名前と高さと幅を持つようなクラスとしました。
Paper.h
typedef struct PaperStruct Paper; extern Paper *Paper_create(char name); extern void Paper_destroy(Paper *paper); extern char Paper_getName(Paper *paper); extern uint16_t Paper_getHeight(Paper *paper); extern uint16_t Paper_getWidth(Paper *paper);
Paper.c
typedef struct PaperStruct {
Cloneable interface;
char name;
uint16_t height;
uint16_t width;
} PaperStruct;
static void *createClone(Cloneable *c) {
Paper *paper = (Paper*)c;
Paper *clone = Paper_create(paper->name);
clone->height = paper->height;
clone->width = paper->width;
return clone;
}
Paper *Paper_create(char name) {
Paper *paper = (Paper*)malloc(sizeof(Paper));
paper->interface.createClone = createClone;
paper->name = name;
paper->height = 100;
paper->width = 200;
return paper;
}
void Paper_destroy(Paper *paper) {
free(paper);
}
char Paper_getName(Paper *paper) {
return paper->name;
}
uint16_t Paper_getHeight(Paper *paper) {
return paper->height;
}
uint16_t Paper_getWidth(Paper *paper) {
return paper->width;
}
Teacherを作る
Prototypeパターンを適用したPaperクラスを使って、大量に複製を作るTeacherを作りましょう。
Teacher.h
#define CRYSTAL_SIZE 100 typedef struct TeacherStruct Teacher; extern Teacher *Teacher_create(); extern void Teacher_destroy(Teacher *teacher); extern Paper **Teacher_createManyCrystals(Teacher *teacher); extern void Teacher_destroyManyCrystals(Teacher *teacher, Paper **paper);
Teacher.c
typedef struct TeacherStruct {
char name;
} TeacherStruct;
static void drawCrystal(Paper *paper) {
// do drawCrystal
}
static void cutAccordanceWithLine(Paper *paper) {
// do cutAccordanceWithLine
}
Teacher *Teacher_create() {
Teacher *teacher = (Teacher*)malloc(sizeof(Teacher*));
teacher->name = 'A';
return teacher;
}
void Teacher_destroy(Teacher *teacher) {
free(teacher);
}
Paper **Teacher_createManyCrystals(Teacher *teacher) {
// create a prototype
Paper *prototype = Paper_create('1');
drawCrystal(prototype);
cutAccordanceWithLine(prototype);
// clone
Paper **crystals = (Paper**)malloc(sizeof(Paper*)*CRYSTAL_SIZE);
crystals[0] = prototype;
for (uint16_t i = 1; i < CRYSTAL_SIZE; i++) {
crystals[i] = (Paper*)Cloneable_createClone((Cloneable*)prototype);
}
return crystals;
}
void Teacher_destroyManyCrystals(Teacher *teacher, Paper **paper) {
for (uint16_t i = 0; i < CRYSTAL_SIZE; i++) {
if (paper[i] != NULL) {
Paper_destroy(paper[i]);
}
}
free(paper);
}
教師はcreateCloneを使って簡単に複製を作ることができていますね。