はじめに
本記事は、GoFデザインパターン解説シリーズの1つです。
今回は、生成に関するパターンの中のFactory Method(ファクトリーメソッド)パターンを、Javaのサンプルコードとともに解説します。
解決したい課題
コードの中でnew SomeClass()のように具体的なクラス名を直接書いてしまうと、そのクラスに強く依存してしまい、「別の種類のクラスに差し替えたい」となったときに、呼び出し元のコードをあちこち修正する必要が出てきます。
例えば「通知を送る」機能で、最初はメール通知だけだったものが、後からSMS通知・Push通知にも対応したくなったとします。
呼び出し元のコードで直接new EmailNotifier()と書いていると、通知の種類が増えるたびに呼び出し元のコードにも手を入れなければなりません。
Factory Methodパターンは、「何のクラスをインスタンス化するか」という決定を、専用の生成メソッド(ファクトリーメソッド)に切り出すことで、この問題を解決します。
クラス構成
- Product(製品): 生成されるオブジェクトの共通インターフェース
- ConcreteProduct(具体的な製品): Productを実装する、具体的なクラス群
- Creator(生成者): ファクトリーメソッドを持つ抽象クラス(またはインターフェース)
- ConcreteCreator(具体的な生成者): ファクトリーメソッドを実装し、特定のConcreteProductを生成するクラス
Javaでの実装例
通知(Notifier)を例に実装してみます。
Product:通知の共通インターフェース
public interface Notifier {
void send(String message);
}
ConcreteProduct:具体的な通知クラス群
public class EmailNotifier implements Notifier {
@Override
public void send(String message) {
System.out.println("[メール送信] " + message);
}
}
public class SmsNotifier implements Notifier {
@Override
public void send(String message) {
System.out.println("[SMS送信] " + message);
}
}
public class PushNotifier implements Notifier {
@Override
public void send(String message) {
System.out.println("[プッシュ通知送信] " + message);
}
}
Creator:ファクトリーメソッドを持つ抽象クラス
public abstract class NotificationService {
// これがファクトリーメソッド。生成方法の決定をサブクラスに委ねる
protected abstract Notifier createNotifier();
// ファクトリーメソッドを使う、共通のビジネスロジック
public void notify(String message) {
Notifier notifier = createNotifier();
notifier.send(message);
}
}
ConcreteCreator:どの通知手段を使うかを決める具体的なクラス
public class EmailNotificationService extends NotificationService {
@Override
protected Notifier createNotifier() {
return new EmailNotifier();
}
}
public class SmsNotificationService extends NotificationService {
@Override
protected Notifier createNotifier() {
return new SmsNotifier();
}
}
public class PushNotificationService extends NotificationService {
@Override
protected Notifier createNotifier() {
return new PushNotifier();
}
}
利用側のコード
public class Main {
public static void main(String[] args) {
NotificationService service1 = new EmailNotificationService();
service1.notify("会員登録が完了しました");
NotificationService service2 = new SmsNotificationService();
service2.notify("認証コードは1234です");
NotificationService service3 = new PushNotificationService();
service3.notify("新着メッセージがあります");
}
}
実行結果:
[メール送信] 会員登録が完了しました
[SMS送信] 認証コードは1234です
[プッシュ通知送信] 新着メッセージがあります
ポイント:共通ロジックと生成ロジックの分離
注目してほしいのは、NotificationServiceのnotify()メソッド(共通のビジネスロジック)は、どのNotifierが使われるか一切知らないという点です。
「どのクラスを生成するか」という決定だけが、サブクラス(EmailNotificationService等)に委ねられています。
新しい通知手段(例えばLINE通知)を追加したくなった場合も、NotificationService本体は一切変更せず、LineNotifierとLineNotificationServiceを新しく追加するだけで対応できます。
これは、後述する「開放閉鎖の原則(拡張には開いていて、修正には閉じている)」というオブジェクト指向設計の基本原則を体現した構造です。
Abstract Factoryパターンとの違い
Factory Methodとよく混同されるのが、次回解説するAbstract Factoryパターンです。
ざっくりとした違いは以下の通りです。
| 観点 | Factory Method | Abstract Factory |
|---|---|---|
| 生成するもの | 1種類の製品を生成するメソッド1つ | 関連する複数種類の製品群を生成する、複数のメソッドを持つオブジェクト |
| 実現方法 | 主に継承(サブクラスでメソッドをオーバーライド) | 主にコンポジション(ファクトリーオブジェクトを注入して使う) |
詳しくは、次回のAbstract Factoryパターンの記事で改めて比較します。
使用場面
- フレームワークが処理の骨格を提供し、具体的な生成処理だけを利用者側にカスタマイズさせたい場合
- 生成するクラスの種類が、設定や実行時の条件によって変わる場合(例: 環境ごとに異なるDBドライバーを生成する)
- 将来的に生成するクラスの種類が増えることが予想され、呼び出し元のコードを変更せずに対応したい場合
まとめ
| 項目 | 内容 |
|---|---|
| 解決する課題 | 具体的なクラス名への直接依存を避け、生成するクラスを柔軟に切り替えたい |
| 実現方法 | インスタンス生成処理を専用メソッド(ファクトリーメソッド)に切り出し、サブクラスに委ねる |
| メリット | 新しい種類を追加する際、既存のコードを変更せずに拡張できる |
| Abstract Factoryとの違い | Factory Methodは1種類の製品、Abstract Factoryは関連する製品群をまとめて生成する |
おすすめ書籍
GoFの23パターンをより深く学びたい方には、以下の書籍がおすすめです。
Java言語のサンプルコードとUMLを使い、初心者にもわかりやすく解説されています。
Java言語で学ぶデザインパターン入門 第3版 [ 結城 浩 ]
※本リンクはアフィリエイトリンクを含みます。


