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

Builderパターンで実装する
SaltWaterを作る
まずはSaltWaterを作りましょう。このクラスは単に塩と水を持つだけです。
SaltWater.h
typedef struct SaltWater {
double salt;
double water;
} SaltWater;
Builderを作る
Builderパターンのキモの1つであるBuilderインタフェースを作りましょう。このサンプルにおけるBuilderは溶液を作るための機能を持ちます。
Builder.h
typedef struct Builder {
void (*addSolute)(struct Builder *builder, double solute);
void (*addSolvent)(struct Builder *builder, double solbent);
void (*abandonSolution)(struct Builder *builder, double solution);
void *(*getResult)(struct Builder *builder);
} Builder;
extern void Builder_addSolute(Builder *builder, double solute);
extern void Builder_addSolvent(Builder *builder, double solvent);
extern void Builder_abandonSolution(Builder *builder, double solution);
extern void *Builder_getResult(Builder *builder);
Builder.c
void Builder_addSolute(Builder *builder, double solute) {
builder->addSolute(builder, solute);
}
void Builder_addSolvent(Builder *builder, double solvent) {
builder->addSolvent(builder, solvent);
}
void Builder_abandonSolution(Builder *builder, double solution) {
builder->abandonSolution(builder, solution);
}
void *Builder_getResult(Builder *builder) {
return builder->getResult(builder);
}
SaltWaterBuilderを作る
BuilderをimplemtnsするSaltWaterBuilderを作りましょう。このBuilderは食塩水を作るためのクラスです。
SaltWaterBuilder.h
typedef struct SaltWaterBuilderStruct SaltWaterBuilder; extern SaltWaterBuilder *SaltWaterBuilder_create(); extern void SaltWaterBuilder_destroy(SaltWaterBuilder * builder);
SaltWaterBuilder.s
typedef struct SaltWaterBuilderStruct {
Builder interface;
SaltWater saltWater;
} SaltWaterBuilderStruct;
void addSolute(Builder *builder, double solute) {
SaltWaterBuilder *swb = (SaltWaterBuilder*)builder;
swb->saltWater.salt += solute;
}
void addSolvent(Builder *builder, double solvent) {
SaltWaterBuilder *swb = (SaltWaterBuilder*)builder;
swb->saltWater.water += solvent;
}
void abandonSolution(Builder *builder, double solution) {
SaltWaterBuilder *swb = (SaltWaterBuilder*)builder;
double saltDelta = solution *
(swb->saltWater.salt / (swb->saltWater.salt + swb->saltWater.water));
double waterDelta = solution *
(swb->saltWater.water / (swb->saltWater.salt + swb->saltWater.water));
swb->saltWater.salt -= saltDelta;
swb->saltWater.water -= waterDelta;
}
void *getResult(Builder *builder) {
SaltWaterBuilder *swb = (SaltWaterBuilder*)builder;
return &swb->saltWater;
}
SaltWaterBuilder *SaltWaterBuilder_create() {
SaltWaterBuilder *builder = (SaltWaterBuilder*)malloc(sizeof(SaltWaterBuilder));
builder->interface.addSolute = addSolute;
builder->interface.addSolvent = addSolvent;
builder->interface.abandonSolution = abandonSolution;
builder->interface.getResult = getResult;
builder->saltWater.salt = 0.0;
builder->saltWater.water = 0.0;
return builder;
}
void SaltWaterBuilder_destroy(SaltWaterBuilder * builder) {
free(builder);
}
このSaltWaterBuilderは食塩水を作っていますが、別の実装として砂糖水を作るSugarWaterBuilderも作成できますね。
Directorを作る
Builderパターンのもう1つのキモであるDirectorクラスを作りましょう。
Director.h
typedef struct DirectorStruct Director; extern Director *Director_create(Builder *builder); extern void Director_destroy(Director *director); extern void Director_construct(Director *director);
Director.c
typedef struct DirectorStruct {
Builder *builder;
} DirectorStruct;
Director *Director_create(Builder *builder) {
Director *director = (Director*)malloc(sizeof(Director));
director->builder = builder;
return director;
}
void Director_destroy(Director *director) {
free(director);
}
void Director_construct(Director *director) {
Builder_addSolvent(director->builder, 100.0);
Builder_addSolute(director->builder, 40.0);
Builder_abandonSolution(director->builder, 70.0);
Builder_addSolvent(director->builder, 100.0);
Builder_addSolute(director->builder, 15.0);
}
DirectorはBuilderの実装に依存していないことがわかりますね。
Directorは次のように使います。
SaltWaterBuilderを使うDirector
SaltWaterBuilder *builder = SaltWaterBuilder_create(); Director *director = Director_create((Builder*)builder); Director_construct(director); SaltWater *saltWater = (SaltWater*)Builder_getResult((Builder*)builder); SaltWaterBuilder_destroy(builder); Director_destroy(director);
SaltWaterBuilder以外のBuilderを渡してあげれば、別の溶液も作ることができますね。