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を使って簡単に複製を作ることができていますね。