Factory Method パターンとは
既存のアプリケーションを流用し、その一部を変更することで新たなアプリケーションを作成する、ということはよくあることだ。アプリケーションおよびコンポーネントをサブクラス化し、変更したいコンポーネントの生成をアプリケーションのサブクラスで行うことで、利用するコンポーネントを切り替える、という手法がFactory Method パターンである。
Factory Method パターンの実装
流用前の構成は、アプリケーション(以下アプリとする)とアプリが使うコンポーネントがいくつか存在し、アプリがコンポーネントの生成を行い、その機能を呼び出しているとする。
class MyApp {
public void execute() {
CompA a = new CompA();/* 直接生成する */
CompB b = new CompB();
a.somethingA();
b.somethingB();
}
}
class CompA {
public void somthingA() {
/* 従来の機能 */
}
}
class CompB {
public void somthingB() {
/* 何らかの機能 */
}
}
流用の設計方針としては、アプリおよびコンポーネントのサブクラス化を行ない、それぞれ抽象クラスー具象クラスの構成にし、アプリの具象クラスとコンポーネントの具象クラスが1つのアプリケーションセットになるようにする。
アプリの元のソースコードをアプリの抽象クラスにおく。コンポーネントの元のソースコードをコンポーネントの具象クラスにおき、コンポーネントの抽象クラスには、インターフェースの宣言をおく。このようにすると、アプリは、コンポーネントの抽象クラスで定義されたインターフェースだけでプログラムされることになる。
このようにした上で、アプリの具象クラスにコンポーネントを生成するメソッドを追加して、アプリの具象クラスに対応するコンポーネントの具象クラスのインスタンスを返すようにする。このメソッドをアプリの抽象クラスにあるインスタンスの生成処理と置き換える。
abstract class MyApp {
abstract public CompA createCompA();
public void execute() {
CompA a = createCompA();/* 具象クラスで生成する */
CompB b = new CompB(); /*今回は手を入れないのでそのまま */
a.somethingA();
b.somethingB();
}
}
class MyApp1 {
public CompA createCompA() {
return new CompA1(); /* 対となる具象クラスのインスタンスを返す */
}
}
class MyApp2 {
public CompA createCompA() {
return new CompA2(); /* 対となる具象クラスのインスタンスを返す */
}
}
abstract class CompA {
abstract public void somthingA();/* インターフェースを定義する */
}
class CompA1 extends CompA {
public void somethingA() {
/* 従来の機能 */
}
}
class CompA2 extends CompA {
public void somethingA() {
/* ここに従来の機能から変更するコードを記述する */
}
}
class CompB {
public void somthingB() {
/* 何らかの機能 */
}
}
このようにしたときのcreateCompA()をfactory methodという。
Factory Method パターンのメリット
すでに存在するアプリケーションを流用して、別のアプリケーションに仕立てる場合に便利なパターンである。既存のコードをほとんど修正しなくて済むというのは最大のメリットだ。
なお、既存のコードをほぼ修正しなくて済むというのは、実はFactory Method パターンの機能ではない。それは「継承」の機能だ。factory methodはコンポーネントの子クラスのオブジェクトを返しているに過ぎない。継承の機能をうまく使えるように、オブジェクトを切り替える、というのがFactory Method パターンの特徴といえるだろう。
Factory Method パターンの適用例
たとえば、DBを読み出してファイルに書く処理のようなものが考えられる。この処理を流用して、ファイルに書くところをメールの発送に代える、というような要求の場合にこのパターンを使うと良いだろう。
一般的には、入出力先を変更する、出力フォーマットを変更する、料金計算方法を変更する、などへの応用になるのではないだろうか。
一方、暗号方法やソート順のような、アルゴリズムの変更に関しては、この方法ではなく、Strategyパターンを検討すべきと考える。というのは、Factory Method パターンを使った場合、アルゴリズムの数だけアプリのサブクラスを作成する必要がある。あまり得策とは思えない。
Abstract Factoryパターンとの比較
Abstract FactoryパターンとFactory Method パターンは、使っているクラスのインスタンスを切り替える、という点では同じ目的である。しかし、切り替えているものは何かという考察をすると、両パターンの違いが明確になるだろう。Abstract Factoryパターンは、(DAOのような)複数の似たような機能のクラス群のなかから1つのクラス群を選択するものだ。一方、Factory Method パターンは複数のアプリケーションから1つを選んだ結果、必要なクラス群を切り替える、というものになる。
このことを頭にいれておくと、どちらのパターンを使うか、悩むことは無いだろう。
- 参考文献 オブジェクト指向における再利用のためのデザインパターン 改訂版 1999/11/1 初版