概要
オブジェクトの生成を呼び出し側に直接 new させると、具象クラスへの依存が広がり、出力形式の追加や切り替えのたびに修正箇所が増えます。Factory Method パターンは、生成処理をサブクラスやメソッドに委譲することで、呼び出し側は Product インターフェースだけを知っていれば済む構造を作ります。この記事では、帳票出力(PDF・HTML・CSV)を題材に Factory Method の基本構造を示し、Java 標準ライブラリの Collections.emptyList や List.of が同じ考え方で設計されていることも確認します。Abstract Factory や Builder との使い分け基準も整理するので、パターン選択で迷ったときの判断材料にしてください。
使いどころ
帳票の出力形式(PDF / HTML / CSV)を設定値で切り替え、出力ロジックを呼び出し側から隠蔽する
通知チャネル(メール / Slack / SMS)をファクトリーで切り替え、送信処理の追加時に既存コードを変更しない
テスト時にモックオブジェクトを返すファクトリーに差し替え、外部依存なしでユニットテストを実行する
コード例
import java.util.List;
public class FactoryMethodSample {
// Product インターフェース
interface Report {
String generate(String title, String content);
}
// 具象 Product
static class PdfReport implements Report {
@Override
public String generate(String title, String content) {
return "[PDF] " + title + ": " + content;
}
}
static class CsvReport implements Report {
@Override
public String generate(String title, String content) {
return "\"" + title + "\",\"" + content + "\"";
}
}
// Creator 抽象クラス
static abstract class ReportFactory {
protected abstract Report createReport();
public String process(String title, String content) {
var report = createReport();
return report.generate(title, content);
}
}
// 具象 Creator
static class PdfReportFactory extends ReportFactory {
@Override
protected Report createReport() { return new PdfReport(); }
}
static class CsvReportFactory extends ReportFactory {
@Override
protected Report createReport() { return new CsvReport(); }
}
public static void main(String[] args) {
var factories = List.of(
new PdfReportFactory(),
new CsvReportFactory()
);
for (var factory : factories) {
System.out.println(factory.process("月次売上", "100万円"));
}
// 標準ライブラリの Factory Method 例
var list = List.of("Java 8", "Java 17", "Java 21");
System.out.println("List.of: " + list);
}
}Version Coverage
var による型推論と record でファクトリーの呼び出しコードが簡潔になる。record をメタ情報の保持に使える。
// Java 17: var + record でメタ情報を付与
var factory = new PdfReportFactory();
var report = factory.createReport();
record ReportType(String type, String title) {}
var meta = new ReportType("PDF", "月次レポート");Library Comparison
注意点
ファクトリーのサブクラスが増えすぎると見通しが悪くなる。生成対象が少数なら static メソッドや enum ベースの簡易ファクトリーで十分な場合がある
Factory Method は生成する「1種類の Product」を切り替えるパターン。関連する複数の Product をまとめて生成するなら Abstract Factory を検討する
ファクトリーの戻り値型を具象クラスにすると委譲の効果が薄れる。必ず Product インターフェースで返すこと
FAQ
Factory Method は1種類の Product の生成をサブクラスに委譲します。Abstract Factory は関連する複数の Product をまとめて生成するファクトリーのインターフェースを定義します。
static ファクトリーメソッドは Simple Factory と呼ばれ、GoF の Factory Method とは別物です。サブクラスによるオーバーライドが不要なら static メソッドで十分です。
Collections.emptyList()、List.of()、Calendar.getInstance() などが典型例です。呼び出し側は内部の実装クラスを意識せずにオブジェクトを受け取れます。