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

図には出てきませんがcompareの引数に使用するHumanクラスも使います。
Strategyパターンで実装する
Humanを作る
比較対象となるHumanを作りましょう。Humanは名前・身長・体重・年齢を持ちます。今回、メンバ変数はpublicなものとしました。
Human.h
typedef struct Human {
char name;
int16_t height;
int16_t weight;
int16_t age;
} Human;
extern Human *Human_create(char name, uint16_t height, uint16_t weight, uint16_t age);
extern void Human_destroy(Human *human);
Human.c
Human *Human_create(char name, uint16_t height, uint16_t weight, uint16_t age) {
Human *human = (Human*)malloc(sizeof(Human));
human->name = name;
human->age = age;
human->height = height;
human->weight = weight;
return human;
}
void Human_destroy(Human *human) {
free(human);
}
Comparatorを作る
Strategyパターンにおける戦略部分のインタフェースComparatorを作りましょう。Human同士の比較ロジックを戦略部分として抜き出します。
Comparator.h
typedef struct Comparator {
int16_t (*compare)(struct Comparator *comparator, Human *human1, Human *human2);
} Comparator;
extern int16_t Comparator_compare(Comparator *comparator, Human *human1, Human *human2);
Comparator.c
int16_t Comparator_compare(Comparator *comparator, Human *human1, Human *human2) {
return comparator->compare(comparator, human1, human2);
}
AgeComparatorを作る
戦略部分の具体的な実装の1つAgeComparatorを作りましょう。AgeComparatorではHumanの年齢を比較します。
AgeComparator.h
typedef struct AgeComparatorStruct AgeComparator; extern AgeComparator *AgeComparator_create(); extern void AgeComparator_destroy(AgeComparator *comparator);
AgeComparator.c
typedef struct AgeComparatorStruct {
Comparator interface;
} AgeComparatorStruct;
static int16_t compare(Comparator *comparator, Human *human1, Human *human2) {
int16_t ret = 0;
if (human1->age > human2->age) {
ret = 1;
} else if (human1->age == human2->age) {
ret = 0;
} else {
ret = -1;
}
return ret;
}
AgeComparator *AgeComparator_create() {
AgeComparator *comparator = (AgeComparator*)malloc(sizeof(AgeComparator));
comparator->interface.compare = compare;
return comparator;
}
void AgeComparator_destroy(AgeComparator *comparator) {
free(comparator);
}
同様に、身長を比較するHeightComparator、体重を比較するWeightComparatorも作成できます。冗長なので本記事では省略します。
MyClassを作る
Comparatorを使って比較を行うMyClassを作りましょう。
MyClass.h
typedef struct MyClassStruct MyClass; extern MyClass *MyClass_create(Comparator *comparator); extern void MyClass_destroy(MyClass *myClass); extern int16_t MyClass_compare(MyClass *myClass, Human *human1, Human *Human2);
MyClass.c
typedef struct MyClassStruct {
Comparator *comparator;
} MyClassStruct;
MyClass *MyClass_create(Comparator *comparator) {
MyClass *myClass = (MyClass*)malloc(sizeof(MyClass));
myClass->comparator = comparator;
return myClass;
}
void MyClass_destroy(MyClass *myClass) {
free(myClass);
}
int16_t MyClass_compare(MyClass *myClass, Human *human1, Human *human2) {
return Comparator_compare(myClass->comparator, human1, human2);
}
MyClassではComparatorを呼んでいるだけです。コンストラクタで渡すComparatorを変えることで比較ロジックを簡単に変更することができますね。
MyClassは次のように使います。
AgeComparator *comparator = AgeComparator_create();
MyClass *myClass = MyClass_create((Comparator*)comparator);
Human *human1 = Human_create('A', 170, 60, 20);
Human *human2 = Human_create('B', 165, 50, 22);
CHECK_EQUAL(-1, MyClass_compare(myClass, human1, human2));
Human_destroy(human1);
Human_destroy(human2);
AgeComparator_destroy(comparator);
MyClass_destroy(myClass);