ファクトリパターン
CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 55/61。
Factory パターンは、オブジェクトの作成を単一の関数に集約します。プログラム全体にmallocと初期化コードを分散させる代わりに、何を作成するかを決定し、すぐに使えるオブジェクトを返す1つの関数を呼び出します。
このパターンは、ポリモーフィズムと組み合わせると特に強力です。factoryは共通のbaseポインターを通じて異なる具体型を返すことができ、呼び出し元から生成の詳細を隠します。呼び出し元は単に「図形」を要求するだけで、factoryが円、長方形、または別の何かを構築するかを決定します。
典型的なファクトリー実装は次のとおりです:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} ShapeType;
Shape* create_shape(ShapeType type) {
switch (type) {
case SHAPE_CIRCLE:
return (Shape*)create_circle(5.0);
case SHAPE_RECTANGLE:
return (Shape*)create_rectangle(4.0, 3.0);
default:
return NULL;
}
}ファクトリは識別子(通常はenum)を受け取り、switch文を使用してどのconstructorを呼び出すかを決定します。実際に作成された型にかかわらず、Shape*を返します。呼び出し側はCircleやRectangleについて知る必要がありません。単に基底型を使って動作します。
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // ポリモーフィックな呼び出し
free_shape(s);このパターンを使うと新しい型を簡単に追加できます。新しい enum 値と factory の新しい case を追加するだけです。コードの残りの部分は変更されません。
チャレンジ
簡単Pet Factoryを構築しましょう。これは、単一のfactory functionを通じてさまざまな種類のペットを作成するシステムです。コード全体に作成ロジックを分散させる代わりに、入力identifierに基づいてどの種類のペットを作成するかを決定する1か所に集約します。
コードを3つのファイルに整理します。
pet.h:PET_DOG、PET_CAT、PET_BIRDの値を持つPetTypeenumをDefineします。speak(const Pet*を受け取り、何も返さない)へのfunction pointerを含むbasePetstructをcreateします。PetTypeを受け取りPet*を返すfactory functioncreate_petと、cleanup用のfree_petfunctionをDeclareします。pet.c: 3つの具体的なpet struct、Dog、Cat、BirdをDefineします。それぞれの最初のmemberとしてPetを埋め込みます。各型のspeak functionをImplementします。- Dogsは
Woof!をprintします。 - Catsは
Meow!をprintします。 - Birdsは
Tweet!をprintします。
create_petfactoryをImplementします。PetTypeに対するswitch statementを使用してcorrectなconstructorをcallし、その結果をPet*として返します。invalidな型の場合はNULLを返します。Allocateされたmemoryをreleaseするためにfree_petをImplementします。- Dogsは
main.c: pet型を表すinteger(dogは0、catは1、birdは2)をReadします。factoryを使用してappropriateなpetをcreateし、basePet*pointerを通じてpolymorphicallyそのspeakfunctionをcallし、その後petをFreeします。
プログラムは、createするpetを示すintegerを1つ入力として受け取ります。
入力が0の場合の出力例:
Woof!入力が1の場合の出力例:
Meow!入力が2の場合の出力例:
Tweet!Factoryパターンの優れた点は、main.cがDog、Cat、Bird structについて知る必要がないことです。base Pet型だけを扱います。後から新しいpet型を追加する場合も、新しいenum値とfactory内の新しいcaseを追加するだけで済み、petを使用するコードを変更する必要はありません。
自分で試してみよう
#include <stdio.h>
#include "pet.h"
int main(void) {
int type;
scanf("%d", &type);
// TODO: ファクトリーを使って適切なペットを作成する
// ヒント: int を PetType にキャストする
// TODO: Pet* ポインタ経由でポリモーフィックに speak 関数を呼び出す
// TODO: ペットを解放する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Cオンラインコンパイラ