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

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

TemplateMethodパターンを確認する

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

 

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

 

TemplateMethodパターンで設計する

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

 

TemplateMethodパターンのクラス図

 

TemplateMethodパターンで実装する

Cuttableを作る

まずはCuttableを作りましょう。ここでは空の構造体として作り、マーカーとしての役目だけを持つようにしました。本来であればcut()メソッドなどがあるべきでしょうね。

 

Cuttable.h

typedef struct Cuttable {
} Cuttable;

 

Woodを作る

続いてCuttableをimplementsするWoodを作りましょう。今回は単に寸法を持つだけの構造体としました。

 

Wood.h

typedef struct WoodStruct Wood;

extern Wood *Wood_create(uint16_t width, uint16_t height, uint16_t length);

extern void Wood_destroy(Wood *wood);

 

Wood.c

typedef struct WoodStruct {
    Cuttable intereface;
    uint16_t width;
    uint16_t height;
    uint16_t length;
} WoodStruct;

Wood *Wood_create(uint16_t width, uint16_t height, uint16_t length) {
    Wood *wood = (Wood*)malloc(sizeof(Wood));
    wood->width = width;
    wood->height = height;
    wood->length = length;

    return wood;
}

void Wood_destroy(Wood *wood) {
    free(wood);
}

 

WoodCutPrintを作る

テンプレートであるWoodCutPrintを作ります。今回私は、draw()、cut()、print()と抽象メソッドが3つもあって少し多いと感じたので、仮想関数テーブルを使う方式で作りました。もちろん、仮想関数テーブルを使わない方式でもまったく問題ありません。

 

WoodCutPrint.h

typedef struct WoodCutPrintStruct WoodCutPrint;

extern void WoodCutPrint_createWoodCutPrint(WoodCutPrint *wcp);

 

WoodCutPrintPrivate.h

typedef struct WoodCutPrintInterface {
    void (*draw)(WoodCutPrint *wcp, Wood *wood);
    void (*cut)(WoodCutPrint *wcp, Wood *wood);
    void (*print)(WoodCutPrint *wcp, Wood *wood);
} WoodCutPrintInterface;

typedef struct WoodCutPrintStruct {
    WoodCutPrintInterface *vtable;
} WoodCutPrintStruct;

 

WoodCutPrint.c

void WoodCutPrint_createWoodCutPrint(CutPrint *wcp) {
    Wood *wood = Wood_create(100, 500, 200);

    wcp->vtable->draw(wcp, (Cuttable*)&wood);
    wcp->vtable->cut(wcp, (Cuttable*)&wood);
    wcp->vtable->print(wcp, (Cuttable*)&wood);

    Wood_destroy(wood);
}

 

TanakasWoodCutPrintを作る

テンプレートで作れたので、田中君の木版画を作ってみましょう。ヘッダファイルは次のようにします。

 

TanakasWoodCutPrint.h

typedef struct TanakasWoodCutPrintStruct TanakasWoodCutPrint;

extern TanakasWoodCutPrint *TanakasWoodCutPrint_create();

extern void TanakasWoodCutPrint_destroy(TanakasWoodCutPrint *tanaka);

 

中身は次のように作ります。

 

TanakasWoodCutPrint.c

static void Tanakas_draw(WoodCutPrint *wcp, Wood *wood) {
    printf("draw the girl friend\n");
}

static void Tanakas_cut(WoodCutPrint *wcp, Wood *wood) {
    printf("cut the wood\n");
}

static void Tanakas_print(WoodCutPrint *wcp, Wood *wood) {
    printf("print dynamically\n");
}

static WoodCutPrintInterface interface = {
        Tanakas_draw,
        Tanakas_cut,
        Tanakas_print
};

typedef struct TanakasWoodCutPrintStruct {
    WoodCutPrint super;
    uint16_t age;
} TanakasWoodCutPrintStruct;

TanakasWoodCutPrint *TanakasWoodCutPrint_create() {
    TanakasWoodCutPrint *tanaka = (TanakasWoodCutPrint*)malloc(sizeof(TanakasWoodCutPrint));
    tanaka->super.vtable = &interface;
    tanaka->age = 15;

    return tanaka;
}

void TanakasWoodCutPrint_destroy(TanakasWoodCutPrint *tanaka) {
    free(tanaka);
}

 

田中君は、draw()、cut()、print()だけを作れば良いだけです。createWoodCutPrint()を丸ごと田中君に任せるより、手順の間違いがないですし、田中君の作業も楽になりますね。

 

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

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