ファクトリーの比較
この記事では、 以下を比較し、 違いを明らかにします:
- ファクトリー
- 生成メソッド
- 静的生成 (つまりファクトリー) メソッド
- 単純ファクトリー
- Factory Method パターン
- Abstract Factory パターン
これらの用語は、 ウェブ上至る所で使われているのが見つけられます。 似たように見えますが、 それぞれ違う意味を持っています。 多くの人々はそのことを知らず、 混乱や誤解につながっています。
ということで、 違いを理解し、 この問題を一気に片付けてみましょう。
1. ファクトリー
ファクトリー (工場) は、 何かを生み出すことになっている関数、 メソッド、 クラスを指す、 曖昧な用語です。 最も一般的な使われ方として、 ファクトリーはオブジェクトを生み出します。 しかしファクトリーは、 ファイルやデータベースのレコードなども生み出すかもしれません。
たとえば、 くだけた場面では、 以下のいずれも 「ファクトリー」 と呼ばれるかもしれません。
- プログラムの GUI を作成する関数またはメソッド
- ユーザーを作成するクラス
- クラスのコンストラクターをある特定の方法で呼び出す静的メソッド
- 生成に関するデザインパターンの一つ
通常、 誰かが 「ファクトリー」 という言葉を使った時、 何を意味しているかは、 文脈から明らかなはずです。 でも疑問に思ったら尋ねていてください。 単にその人がよくわかっていないだけかもしれません。
2. 生成メソッド
生成メソッド (creation method) は、 『パターン指向リファクタリング入門』 の中で、 「オブジェクトを生成するメソッド」 と定義されています。 この意味するところはつまり、 Factory Method パターンの結果は、 生成メソッドですが、 逆は必ずしも真ではない、 ということです。 また、 「生成メソッド」 の用語は、 Martin Fowler (マーティン・ファウラー) 氏が 『リファクタリング: 既存のコードを安全に改善する』 の中で言う 「ファクトリー・メソッド」 という用語、 Joshua Bloch (ジョシュア・ブロック) 氏が 『Effective Java』 (邦題同) の中で言う 「静的ファクトリー・メソッド」 という用語と置き換え可能です。
実際のところ、 生成メソッドはコンストラクター呼び出しのラッパーにすぎません。 単に意図をより良く言い表せる名前とも言えます。 一方で、 コンストラクターの変更からコードを隔離する一助になるかもしれません。 あるいは新規オブジェクトを作成する代わりに、 既存のものを返すなどの特定のロジックを含ませることすらできます。
新しいオブジェクトを生み出すからという理由だけで、 多くの人たちがそのようなメソッドのことを 「ファクトリー・メソッド」 と呼びます。 メソッドはオブジェクトを作成し、 すべてのファクトリーはオブジェクトを作成するので、 これは明らかにファクトリー・メソッドだ、 という単純な論理に基づいています。 当然のことながら、 本物の Factory Method パターンのことを話す時に、 大混乱となります。
下記の例では、 next
は、 生成メソッドです。
3. 静的生成メソッド
静的生成メソッド (static creation method) は、 static
と宣言された生成メソッドです。 言い換えると、 クラスに対して呼び出すことができ、 呼び出しに際してオブジェクトを必要としません。
この種のメソッドのことを誰かが 「静的ファクトリー・メソッド」 と呼んだからと言って驚かないでください。 ただの習慣です。 Factory Method は、 継承に頼ったデザインパターンです。 それを static
としてしまうと、 サブクラスではもう拡張できず、 このパターンの目的に反したものとなります。
静的生成メソッドが新規オブジェクトを返すなら、 コンストラクターの代替となります。
以下の場合に便利かもしれません:
-
異なる目的のために異なるコンストラクターがいくつか必要だが、 コンストラクターのシグネチャーが一致してしまう時。 たとえば、
Random(int max)
とRandom(int min)
の両方を持つことは、 Java、 C++、 C#、 そして他の多くの言語では不可能です。 この問題点の回避方法として一番よく使われる方法は、 デフォルト・コンストラクターを呼んで、 その後適切な値を設定する静的メソッドをいくつか作成することです。 -
新規オブジェクトを作成する代わりに、 既存のオブジェクトを再利用したい時。 ([Singleton] パターンをご覧ください。) ほとんどのプログラミング言語では、 コンストラクターはクラスの新インスタンスを返さなければなりません。 静的作成メソッドは、 この制限の回避策です。 静的メソッド内部では、 コンストラクターを呼び出して新鮮なインスタンスを作成すべきか、 キャッシュにある既存オブジェクトを返すべきかを、 自分のコードが決めます。
下記の例では、 load
メソッドは、 静的生成メソッドで、 ユーザーをデータベースから取得する便利な方法を提供します。
4. 単純ファクトリー・パターン
単純ファクトリー (simple factory) パターン は、 巨大な条件分岐のついた生成メソッドを持つクラスのことです。 メソッドのパラメーターに基づき、 どのプロダクトのクラスをインスタンス化すべきかを決め、 生成し、 返します。
人々は通常、 単純ファクトリーを一般的なファクトリーか、 あるいは生成に関するデザインパターンのうちの一つと勘違いします。 大抵の場合、 単純ファクトリーは、 Factory Method パターンか Abstract Factory パターンを導入する時の中間ステップです。
単純ファクトリーは、 一つのクラス中の一つのメソッドとして表現されます。 時間が経過するにつれて、 このメソッドは大きくなりすぎ、 メソッドの一部をサブクラスに抽出すべきかどうか検討を始めます。 そして抽出を何回か繰り返すと、 典型的な Factory Method パターンになっていることに気が付くでしょう。
ちなみに、 単純ファクトリーを abstract
と宣言さえすれば、 魔法のように Abstract Factory パターンになるわけではありません。
単純ファクトリーの例です:
5. Factory Method パターン
Factory Method は、 生成に関するデザインパターンの一つで、 生成するオブジェクトのインターフェースを宣言し、 サブクラスで作成されるオブジェクトの型を自由に変更できるようにします。
もし基底クラスに生成メソッドがあり、 それをサブクラスで拡張していたら、 Factory Method が使われているのかもしれません。
6. Abstract Factory パターン
Abstract Factory は、 生成に関するデザインパターンの一つで、 関連あるいは依存関係にあるオブジェクトのファミリーを、 具象クラスを指定せずに可能にします。
「オブジェトのファミリー」 って何だ、 ですって? たとえば、 このクラスの集まりを考えてみてください: 輸送手段
+エンジン
+制御方法
。 これらには、 以下のような、 変種があるかもしれません:
-
車
+燃焼エンジン
+ハンドル
-
飛行機
+ジェットエンジン
+操縦桿
あなたのプログラムにプロダクトのファミリーのようなものがないのであれば、 Abstract Factory を使う必要はありません。
繰り返しますが、 多くの人が Abstract Factory のことを、 abstract
と宣言された単純ファクトリーと勘違いしています。 十分注意してください。
後書き
違いがわかったところで、 これらのデザインパターンについて改めて再読してみてください: