C言語でGoFのBridgeパターンを実装します。
Bridgeパターンを確認する
まずはBridgeパターンを確認しましょう。TECHSCOREさんのBridgeパターンの解説記事をご参照ください。
https://www.techscore.com/tech/DesignPattern/Bridge.html/
Bridgeパターンで設計する
TECHSCOREさんのサンプルコードをC言語に移植します。クラス図にすると次のようになります。
Bridgeパターンで実装する
SortImplを作る
まずは実際にソート処理を行うSortImpl系統を作っていきましょう。AbstractなSortImplは次のように作ります。
SortImpl.h
typedef struct SortImpl { void (*sort)(struct SortImpl *impl, uint16_t *list); } SortImpl; extern void SortImpl_sort(SortImpl *impl, uint16_t *list);
SortImpl.c
void SortImpl_sort(SortImpl *impl, uint16_t *list) { impl->sort(impl, list); }
QuickSortImplを作る
SortImplの実装クラスの1つQuickSortImplを作りましょう。
QuickSortImpl.h
typedef struct QuickSortImplStruct QuickSortImpl; extern QuickSortImpl *QuickSortImpl_create(); extern void QuickSortImpl_destroy(QuickSortImpl *impl);
QuickSortImpl.c
typedef struct QuickSortImplStruct { SortImpl super; } QuickSortImplStruct; static void sort(SortImpl *impl, uint16_t *list) { // do quick sort } QuickSortImpl *QuickSortImpl_create() { QuickSortImpl *quick = (QuickSortImpl*)malloc(sizeof(QuickSortImpl)); quick->super.sort = sort; return quick; } void QuickSortImpl_destroy(QuickSortImpl *impl) { free(impl); }
もう1つの実装クラスであるBubbleSortImplも同様にして作れますので、ここでは省略します。
Sorterを作る
SortImplを使用するSorterを作りましょう。Sorterは機能追加されるので、継承したクラスから参照できるように構造体の仕様はSorterPrivate.hに入れておきます。
Sorter.h
typedef struct SorterStruct Sorter; extern Sorter *Sorter_create(SortImpl *impl); extern void Sorter_destroy(Sorter *sorter); extern void Sorter_sort(Sorter *sorter, uint16_t *list);
SorterPrivate.h
typedef struct SorterStruct { SortImpl *impl; } SorterStruct;
Sorter.c
Sorter *Sorter_create(SortImpl *impl) { Sorter *sorter = (Sorter*)malloc(sizeof(Sorter)); sorter->impl = impl; return sorter; } void Sorter_destroy(Sorter *sorter) { free(sorter); } void Sorter_sort(Sorter *sorter, uint16_t *list) { SortImpl_sort(sorter->impl, list); }
TimerSorterを作る
Sorterを継承し、timeSort()メソッドを機能追加するTimerSorterを作りましょう。
TimerSorter.h
typedef struct TimerSorterStruct TimerSorter; extern TimerSorter *TimerSorter_create(SortImpl *impl); extern void TimerSorter_destroy(TimerSorter *sorter); extern void TimerSorter_timerSort(TimerSorter *sorter, uint16_t *list);
TimerSorter.c
typedef struct TimerSorterStruct { Sorter super; } TimerSorterStruct; TimerSorter *TimerSorter_create(SortImpl *impl) { TimerSorter *sorter = (TimerSorter*)malloc(sizeof(TimerSorter)); sorter->super.impl = impl; return sorter; } void TimerSorter_destroy(TimerSorter *sorter) { free(sorter); } void TimerSorter_timerSort(TimerSorter *sorter, uint16_t *list) { clock_t start = clock(); SortImpl_sort(sorter->super.impl, list); clock_t end = clock(); printf("elapsed time = %ld\n", (end - start)); }
Sorterを使う場合と、TimerSorterを使う場合を見比べて、Bridgeパターンの効果を確認しておきましょう。
Sorterを使う場合
QuickSortImpl *impl = QuickSortImpl_create(); Sorter *sorter = Sorter_create((SortImpl*)impl); Sorter_sort(sorter, NULL); QuickSortImpl_destroy(impl); Sorter_destroy(sorter);
TimerSorterを使う場合
BubbleSortImpl *impl = BubbleSortImpl_create(); TimerSorter *sorter = TimerSorter_create((SortImpl*)impl); Sorter_sort((Sorter*)sorter, NULL); TimerSorter_timerSort(sorter, NULL); BubbleSortImpl_destroy(impl); TimerSorter_destroy(sorter);
Sorterの場合はクイックソートを使っています。TimerSorterの場合は、バブルソートを使いつつ、timerSort()メソッドの機能追加が実現できていますね。
もちろん、TimerSorterでバブルソートを重複して作ることはしていません。