C言語でPrototypeパターン【オブジェクト指向】

C言語でGoFのPrototypeパターンを実装します。

Prototypeパターンを確認する

まずはPrototypeパターンを確認しましょう。TECHSCOREさんのPrototypeパターンの解説記事をご参照ください。

 

https://www.techscore.com/tech/DesignPattern/Prototype.html/

 

Prototypeパターンで設計する

TECHSCOREさんのサンプルコードをC言語に移植します。クラス図は下記のようになります。

 

Prototypeパターンのクラス図

 

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

 

目次:C言語でGoFのデザインパターン【オブジェクト指向】

ソースコード:https://github.com/yuksblog/c_gof_design_pattern