ファクトリーメソッドパターン(Factory Method Pattern)は、オブジェクト指向プログラミングにおけるデザインパターンの一つで、主に「インスタンス生成の過程をサブクラスに委ねる」ことを目的としています。このパターンでは、特定のクラスでオブジェクトを生成するのではなく、サブクラスがオブジェクト生成のロジックを実装するため、柔軟で拡張性のある設計が可能になります。
具体的には、クラス内に「ファクトリーメソッド」と呼ばれるメソッドを設け、このメソッドがオブジェクトを生成します。ファクトリーメソッドは、インターフェースまたは抽象クラスとして宣言され、実際のオブジェクト生成はサブクラスで行われます。
例えば、アプリケーションが複数の異なるデータベース(MySQL、PostgreSQLなど)を扱う場合、データベース接続オブジェクトの生成をファクトリーメソッドに委ねることで、各データベースに対するオブジェクト生成のロジックをサブクラスで個別に定義できます。これにより、特定のデータベース固有の実装に依存しない柔軟な設計が可能になります。
ファクトリーメソッドパターンの特徴
ファクトリーメソッドパターンには、いくつかの特徴があります。
- オブジェクト生成のカプセル化
オブジェクトの生成プロセスがメソッド内部に隠蔽されているため、クライアント側は生成の詳細に依存せず、インターフェースを介してオブジェクトを利用できます。この設計により、クラスが他のクラスに強く依存するのを防ぎ、コードの保守性が向上します。
- 拡張性の向上
新しいクラスやオブジェクトを追加する際、既存のコードに影響を与えることなく、サブクラスを追加するだけで対応できます。例えば、新しいデータベースタイプが追加された場合でも、既存のファクトリーメソッドを変更せずに、適切なサブクラスを作成すれば対応可能です。
- 依存性の低減
ファクトリーメソッドを使用することで、クラス間の依存関係が緩和されます。オブジェクト生成の責任が特定のクラスに集中せず、複数のクラスに分散されるため、システム全体のモジュール性が向上します。
- 再利用性の向上
ファクトリーメソッドを使用することで、同じインターフェースや抽象クラスを介して異なるオブジェクトを生成できるため、再利用性が高まります。これにより、コードの重複を減らし、保守コストを低く抑えることができます。
TypeScriptでのファクトリーメソッドパターン実装例
// 抽象クラス(またはインターフェース)
abstract class Animal {
constructor(protected name: string) {}
abstract speak(): void;
}
// 具象クラス
class Dog extends Animal {
speak(): void {
console.log(`${this.name}はワンワンと鳴いています`);
}
}
class Cat extends Animal {
speak(): void {
console.log(`${this.name}はニャーと鳴いています`);
}
}
// ファクトリーメソッドを持つ抽象クラス
abstract class AnimalFactory {
abstract createAnimal(name: string): Animal;
}
// サブクラスで具体的なオブジェクト生成を実装
class DogFactory extends AnimalFactory {
createAnimal(name: string): Animal {
return new Dog(name);
}
}
class CatFactory extends AnimalFactory {
createAnimal(name: string): Animal {
return new Cat(name);
}
}
// クライアントコード
const main = () => {
// 名前を引数に渡す例
let factory: AnimalFactory = new DogFactory();
let animal: Animal = factory.createAnimal("ポチ");
animal.speak(); // 出力: ポチはワンワンと鳴いています
factory = new CatFactory();
animal = factory.createAnimal("タマ");
animal.speak(); // 出力: タマはニャーと鳴いています
}
main();
- 抽象クラス:
abstract class
として定義し、抽象メソッドspeak()
を持たせています。このメソッドは、各具体的なサブクラスで実装されます。 - 具象クラスの実装:
Dog
とCat
クラスは、Animal
クラスを継承し、それぞれのspeak()
メソッドをオーバーライドして具体的な動作を実装しています。 - ファクトリーメソッドの実装:
AnimalFactory
という抽象クラスにcreateAnimal()
という抽象メソッドを定義し、具象ファクトリ(DogFactory
やCatFactory
)で具体的なオブジェクトを生成します。 - クライアントコード: クライアントコードでは、
DogFactory
やCatFactory
を使って、それぞれDog
やCat
オブジェクトを生成し、その動作を呼び出しています。
ファクトリーメソッドパターンの利用シーン
ファクトリーメソッドパターンは、以下のようなシチュエーションで有効に活用されます。
- 具体的なクラスに依存せずにインスタンスを生成したい場合
例えば、複数のサブクラスが存在し、それらを動的に切り替える必要がある場合、ファクトリーメソッドを使うことで柔軟な生成が可能になります。
- 新しい機能を拡張したいが、既存のコードに影響を与えたくない場合
新しい種類のオブジェクトが必要になったとき、ファクトリーメソッドを追加するだけで既存のクライアントコードを変更せずに対応できます。
- オブジェクト生成が複雑な場合
単純なインスタンス生成ではなく、初期化プロセスが複雑な場合や条件に応じて異なるオブジェクトを生成する場合に、このパターンが有効です。
まとめ
ファクトリーメソッドパターンは、オブジェクト生成の柔軟性と拡張性を高めるために非常に便利なデザインパターンです。特に、クラス間の依存関係を減らし、新しい機能の追加や拡張を容易にする点で大きなメリットがあります。これにより、コードの保守性が向上し、システム全体の設計がよりモジュール化され、変更に強い構造になります。
このパターンを適切に活用することで、開発の効率化やコードの品質向上を図ることができるため、ぜひプロジェクトに取り入れてみてください。