「オブジェクトの生成処理が複雑になってコードが読みにくい」「新しいクラスを追加するたびに既存のコードを修正しなければならない」といった悩みを抱えていませんか?本記事では、そのような課題を解決するGoFデザインパターンの1つである「ファクトリーメソッド(Factory Method)」について、基本概念から具体的な実装例までをわかりやすく解説します。
記事のポイント
- ファクトリーメソッドは、オブジェクトの生成処理をサブクラスに委譲するデザインパターンです。
- 生成ロジックと利用ロジックを分離することで、コードの保守性と拡張性が向上します。
- 新しい種類のオブジェクトを追加する際も、既存のCreatorや既存のConcreteCreatorを変更せず、新しいConcreteProductとConcreteCreatorを追加して拡張できます。
- 具体的なProductへの依存をCreatorから分離し、Productインターフェースを介して柔軟に製品を扱える設計が実現できます。
ファクトリーメソッド(Factory Method)パターンとは?
ファクトリーメソッド(Factory Method) は、GoF(Gang of Four)によって定義された23のデザインパターンのうち、「生成に関するパターン」の1つです。
オブジェクトを生成するためのインターフェース(APIAPI [エーピーアイ]Application Programming Interface。異なるソフトウェア間の接続口)を定義しますが、実際にどのクラスのインスタンスを生成するかはサブクラスに決定させます。直訳すると「工場(Factory)メソッド」であり、その名の通り「インスタンスを生成する工場」としての役割を持つメソッドを定義します。
解決できる課題とデザインパターン導入の必要性
通常のオブジェクト指向プログラミングでは、newキーワードを使って直接クラスをインスタンス化します。しかし、この方法には以下のような問題が発生することがあります。
- 密結合の発生:利用側(クライアント)のコードが、具体的な具象クラス(実装クラス)に強く依存してしまう。
- コードの複雑化:条件分岐(if文やswitchswitch [スイッチ]ネットワーク内で複数の機器を接続し、必要な宛先のみにデータを送る機器文)によって生成するオブジェクトを切り替えるロジックが散在し、可読性が低下する。
- 変更への弱さ:新しい種類のクラスを追加するたびに、利用側のコード(条件分岐など)を修正する必要がある。
ファクトリーメソッドパターンは、オブジェクトの生成処理をファクトリーメソッドとして切り出し、具体的な生成方法をサブクラスに委譲することで、生成と利用の結び付きを弱めます。
ファクトリーメソッドの構造と4つの登場人物(クラス構成)
ファクトリーメソッドパターンには、主に4つの登場人物(役割)が存在します。
- Product(製品)
生成されるオブジェクトが実装すべきインターフェース(または抽象クラス)を定義します。 - ConcreteProduct(具体的な製品)
Productインターフェースを実装した具体的なクラスです。 - Creator(作成者)
オブジェクトを生成するためのメソッド(ファクトリーメソッド)を定義するクラス(またはインターフェース)です。※必ずしも抽象メソッドにする必要はなく、デフォルトの実装(具体的な製品の生成)を持たせることも可能です。このクラスは、具体的な製品が何であるかを知らずに、Productを操作するロジックを持つことができます。 - ConcreteCreator(具体的な作成者)
Creatorを継承し、ファクトリーメソッドを実装して具体的なConcreteProductのインスタンスを生成します。
ファクトリーメソッドパターンの具体的な実装例(Javaコード解説)
ここでは、JavaJava [ジャバ]オブジェクト指向プログラミング言語を使ったシンプルな実装例を紹介します。「ドキュメント(Document)」を作成するアプリケーションを想定します。
1. Product(製品)インターフェースの定義
まず、生成されるオブジェクトの共通インターフェースを定義します。
// Productpublic interface Document { void open(); void close();}2. ConcreteProduct(具体的な製品)の実装
次に、具体的なドキュメントの種類(PDFやWordなど)を実装します。
// ConcreteProduct Apublic class PdfDocument implements Document { @Override public void open() { System.out.println("PDFドキュメントを開きます。"); }
@Override public void close() { System.out.println("PDFドキュメントを閉じます。"); }}
// ConcreteProduct Bpublic class WordDocument implements Document { @Override public void open() { System.out.println("Wordドキュメントを開きます。"); }
@Override public void close() { System.out.println("Wordドキュメントを閉じます。"); }}3. Creator(作成者)クラスの作成
オブジェクト生成のインターフェースを持つクラスを定義します。
// Creatorpublic abstract class Application { // これがファクトリーメソッド(※ここでは分かりやすさのため抽象メソッドとしていますが、デフォルト実装を持たせることも可能です) protected abstract Document createDocument();
// 製品を利用する共通ロジック public void newDocument() { Document doc = createDocument(); doc.open(); // 共通の初期化処理など }}4. ConcreteCreator(具体的な作成者)でのインスタンス生成
最後に、具体的なオブジェクトを生成するクリエイタークラスを作成します。
// ConcreteCreator Apublic class PdfApplication extends Application { @Override protected Document createDocument() { return new PdfDocument(); }}
// ConcreteCreator Bpublic class WordApplication extends Application { @Override protected Document createDocument() { return new WordDocument(); }}クライアント側の実行例と動作確認
クライアント側のコードは、どの具体的なドキュメントが生成されているかを意識せずに利用できます。
public class Main { public static void main(String[] args) { Application pdfApp = new PdfApplication(); pdfApp.newDocument(); // "PDFドキュメントを開きます。" が出力される
Application wordApp = new WordApplication(); wordApp.newDocument(); // "Wordドキュメントを開きます。" が出力される }}ファクトリーメソッドパターンを採用するメリット・デメリット
疎結合化と依存関係の整理
- 拡張性(Open-Closed Principleに沿った設計)
新しい製品(例えばExcelDocument)を追加する場合、既存のApplicationや既存のConcreteCreatorを変更せず、新しいExcelDocumentとExcelApplicationを追加できます。なお、クライアント側でExcelを利用するためのコード追加は必要です。 - 具体的なProductへの依存排除
Creatorは具体的なProductではなく、Productという抽象型を通じて製品を扱うため、CreatorとConcreteProductの直接的な依存を減らせます。
注意すべきデメリット(クラス数の増加)
- クラス数の増加
製品の種類が増えると、それに対応するConcreteCreatorの追加が必要になる場合があり、クラス数が増えて構造が複雑になる可能性があります。 - コードがやや冗長になる
非常にシンプルなオブジェクト生成であれば、単純なnewやSimple Factory(単一のクラスでswitch文を使って生成)の方が適している場合があります。
まとめ:ファクトリーメソッドで保守性の高い設計を実現しよう
ファクトリーメソッド(Factory Method)パターンは、オブジェクトの生成ロジックをカプセル化し、システムの拡張性と保守性を高める設計手法です。
「Creatorのサブクラスによって、生成するConcreteProductを切り替えたい場合」や「将来的に新しい製品クラスが追加される可能性が高い場合」に特に有効です。デザインパターンの基本中の基本とも言えるパターンですので、ぜひ実際のプロジェクトでも活用してみてください。
【参考情報】
以上で本記事の解説を終わります。
よいITライフを!
人気記事
- 1
- 2
- 3
- 4
- 5
思考の整理というテーマを、実務ですぐに使える具体的な「技術」として落とし込んだ一冊です。