プログラムを設計する際、オブジェクトの生成方法を適切に管理することは、保守性や拡張性の高いコードを書く上で非常に重要な課題です。
そのような場面で役立つのが、ファクトリパターンと呼ばれるデザインパターンです。
GoF(Gang of Four)によって体系化された生成パターンのひとつであり、JavaやC#などオブジェクト指向言語を使った開発において広く採用されています。
本記事では、ファクトリパターンの意味・定義から、その仕組みと具体的な使い方、実際のコード例まで、わかりやすく解説していきます。
デザインパターンの基礎を学びたい方や、オブジェクト指向設計の理解を深めたい方にとって、役立つ内容となっています。
ぜひ最後までお読みいただき、ファクトリパターンの概念と実践的な使い方を習得してください。
ファクトリパターンとは何か?その本質と定義をわかりやすく解説
それではまず、ファクトリパターンの基本的な意味と定義について解説していきます。
ファクトリパターンとは、オブジェクトの生成処理を専門のクラスやメソッドに委譲することで、生成処理と利用処理を分離するデザインパターンです。
「ファクトリ(Factory)」とは英語で「工場」を意味し、まさに工場がさまざまな製品を生産するように、ファクトリパターンでは専用のクラスがオブジェクトを生産する役割を担います。
デザインパターンとGoFにおける位置づけ
デザインパターンとは、ソフトウェア設計における典型的な問題に対する再利用可能な解決策を体系化したものです。
1994年にErich Gamma、Richard Helm、Ralph Johnson、John Vlissidesの4名(通称GoF:Gang of Four)によって著書「Design Patterns」で23のパターンが紹介され、現代のオブジェクト指向設計の基礎となっています。
ファクトリパターンは、GoFのデザインパターンの中で生成パターン(Creational Patterns)に分類されます。
生成パターンとはオブジェクトの生成に関する問題を解決するためのパターン群であり、ファクトリメソッドパターン、抽象ファクトリパターン、シングルトンパターンなどが含まれます。
ファクトリパターンという言葉は広義には「Simple Factory」「Factory Method」「Abstract Factory」の三つを含む場合がありますが、狭義にはFactory Methodパターンを指すことが多いです。
ファクトリパターンが解決する設計上の問題
ファクトリパターンは、具体的にどのような設計上の問題を解決するのでしょうか。
オブジェクト指向プログラミングでは、クライアントコード(利用側)が直接具体的なクラスをインスタンス化(newする)と、クライアントと具体クラスの間に強い依存関係が生まれます。
この状態では、具体クラスが変更・追加された際にクライアントコードも修正が必要となり、保守コストが増大します。
ファクトリパターンを使うと、クライアントコードは具体的なクラス名を知る必要がなくなります。「どのクラスを使うか」という決定をファクトリに任せることで、クライアントと具体クラスの結合度を下げ、変更に強い設計が実現できます。これがファクトリパターンの本質的な価値です。
ファクトリパターンの基本構造と登場人物
ファクトリパターンの基本構造を理解するために、主要な登場人物(役割)を整理しましょう。
| 役割名 | 説明 | Javaでの対応 |
|---|---|---|
| Product(製品) | 生成されるオブジェクトの共通インターフェース | インターフェース・抽象クラス |
| ConcreteProduct(具体製品) | Productを実装した具体的なクラス | 具体クラス |
| Creator(作成者) | Productを生成するメソッドを持つ抽象クラス | 抽象クラス・インターフェース |
| ConcreteCreator(具体作成者) | 具体的な生成処理を実装するクラス | 具体クラス |
Creatorはオブジェクトを生成する「ファクトリメソッド」を定義しますが、具体的にどのProductを生成するかはConcreteCreatorに委ねます。
クライアントはCreatorインターフェースを通じてオブジェクトを取得するため、ConcreteProductの具体的な型を知る必要がありません。
ファクトリパターンの具体的な実装例(Java・C#)
続いては、ファクトリパターンの具体的な実装例をJavaとC#のコードで確認していきます。
実際のコードを通じて、パターンの動作原理と実装の流れをより具体的に理解することができます。
動物を生成するシンプルな例を使って、ファクトリパターンの基本を見ていきましょう。
Simple Factoryの実装例(Java)
まず最も単純な形態であるSimple Factory(静的ファクトリ)のJava実装例を見ていきます。
// Product(製品)インターフェース
interface Animal {
void speak();
}
// ConcreteProduct(具体製品)
class Dog implements Animal {
public void speak() { System.out.println(“ワンワン”); }
}
class Cat implements Animal {
public void speak() { System.out.println(“ニャー”); }
}
// SimpleFactory(ファクトリクラス)
class AnimalFactory {
public static Animal create(String type) {
if (type.equals(“dog”)) return new Dog();
if (type.equals(“cat”)) return new Cat();
throw new IllegalArgumentException(“Unknown type: ” + type);
}
}
// クライアントコード
Animal animal = AnimalFactory.create(“dog”);
animal.speak(); // ワンワン
このSimple Factoryでは、クライアントは文字列でオブジェクトの種類を指定するだけでよく、DogやCatクラスを直接インスタンス化する必要がありません。
ただし、新しい動物を追加する際はAnimalFactoryクラスを修正する必要があるため、オープン・クローズド原則(OCP)に違反するという問題があります。
Factory Methodパターンの実装例(C#)
Simple Factoryの問題を解決するのがFactory Methodパターンです。C#での実装例を見ていきましょう。
// Product(製品)抽象クラス
abstract class Animal {
public abstract void Speak();
}
// ConcreteProduct
class Dog : Animal {
public override void Speak() => Console.WriteLine(“ワンワン”);
}
class Cat : Animal {
public override void Speak() => Console.WriteLine(“ニャー”);
}
// Creator(抽象ファクトリ)
abstract class AnimalCreator {
public abstract Animal CreateAnimal();
}
// ConcreteCreator
class DogCreator : AnimalCreator {
public override Animal CreateAnimal() => new Dog();
}
class CatCreator : AnimalCreator {
public override Animal CreateAnimal() => new Cat();
}
Factory Methodパターンでは、新しい動物(例:Bird)を追加する場合も既存のクラスを修正する必要がなく、BirdクラスとBirdCreatorクラスを新規追加するだけで対応できます。
これにより、オープン・クローズド原則(拡張に開いており、修正に閉じている)が守られた設計が実現します。
実装時のポイントと注意事項
ファクトリパターンを実装する際は、いくつかの重要なポイントに注意する必要があります。
まず、ProductはインターフェースまたはAbstractクラスで定義し、クライアントコードが具体クラスに依存しないようにすることが基本です。
ファクトリメソッドの戻り値型は必ず抽象型(インターフェース)にし、具体型を返さないことが重要なルールです。
生成するオブジェクトの種類が増えることが予想される場合は、最初からFactory Methodパターンを採用する方が後の拡張が容易です。
一方、生成するオブジェクトの種類が固定で変更の可能性が低い場合は、Simple Factoryのシンプルな実装で十分なケースもあります。
ファクトリパターンの設計原則との関係
続いては、ファクトリパターンとSOLID原則などの設計原則との関係を確認していきます。
ファクトリパターンを深く理解するためには、その背後にある設計原則を理解することが重要です。
設計原則との関係を把握することで、ファクトリパターンを適切な場面で正しく活用する判断力が養われます。
依存性逆転原則(DIP)との関係
ファクトリパターンは、SOLID原則の中でも特に依存性逆転原則(DIP:Dependency Inversion Principle)と密接な関係があります。
DIPとは「高レベルのモジュールは低レベルのモジュールに依存してはならない。両方とも抽象に依存すべきである」という原則です。
ファクトリパターンを使用することで、クライアント(高レベルモジュール)は具体的な製品クラス(低レベルモジュール)ではなく、抽象インターフェースに依存する構造が実現されます。
この結果、具体的な実装クラスが変更・追加されてもクライアントコードへの影響が最小限に抑えられます。
オープン・クローズド原則(OCP)との関係
オープン・クローズド原則(OCP)は「ソフトウェアのエンティティは拡張に対して開いており、修正に対して閉じていなければならない」という原則です。
Simple Factoryはif-elseやswitch文によって生成するクラスを切り替えるため、新しい製品を追加するたびにファクトリクラスの修正が必要となり、OCPに違反しやすい構造です。
Factory Methodパターンでは、新しい製品の追加時に既存クラスを修正せずに新しいConcreteCreatorクラスを追加するだけで対応できるため、OCPをより適切に守った設計が実現します。
設計の拡張性を重視する場合は、Factory MethodパターンやAbstract Factoryパターンを選択することが推奨されます。
単一責任原則(SRP)との関係
単一責任原則(SRP)は「クラスは変更する理由をひとつだけ持つべきである」という原則です。
ファクトリパターンを使用することで、オブジェクトの生成責任をファクトリクラスに集約し、クライアントクラスからオブジェクト生成の責任を取り除くことができます。
これにより、各クラスが持つ責任が明確化され、SRPに準拠したクリーンな設計が実現します。
生成ロジックと業務ロジックが分離されることで、コードの可読性・テスト容易性も向上し、品質の高いソフトウェア開発につながります。
まとめ
本記事では、ファクトリパターンの基本的な定義と意味から、デザインパターン・GoFにおける位置づけ、JavaとC#での具体的な実装例、そして設計原則との関係まで幅広く解説しました。
ファクトリパターンはオブジェクトの生成処理を分離することで結合度を下げ、拡張性・保守性の高いコードを実現する非常に重要なデザインパターンです。
Simple Factory、Factory Method、Abstract Factoryの三段階の発展形があり、それぞれが異なる設計上の問題を解決します。
DIP・OCP・SRPとの深い関係を理解することで、ファクトリパターンを単なるテクニックとしてではなく、設計思想として本質的に活用できるようになります。
JavaやC#でのオブジェクト指向開発において、ファクトリパターンは実務でも頻繁に使われる重要なパターンですので、ぜひ積極的に習得・活用してみてください。