概要
Factory Method がひとつの Product の生成を切り替えるのに対し、Abstract Factory は「関連する複数の Product をまとめて」生成するインターフェースを定義します。たとえば DB 接続先を MySQL と PostgreSQL で切り替えるとき、Connection と Statement を別々のファクトリーで生成すると組み合わせの不整合が起きかねません。Abstract Factory を使えば、ファクトリーを差し替えるだけで関連するオブジェクト群が一貫して切り替わります。この記事では DB アクセス層を題材に Abstract Factory の構造を示し、Factory Method との使い分け基準、Java 17 の record を活用した簡潔な製品クラス定義、Java 21 の sealed interface による型安全な製品分岐を整理します。
使いどころ
開発環境と本番環境で DB(MySQL / PostgreSQL)を切り替え、Connection・Statement を一貫して生成する
UI テーマ(ライト / ダーク)に応じたボタン・テキスト・背景のスタイルセットをまとめて生成する
帳票出力で「和文セット(明朝 + 縦書き + 和暦)」と「英文セット(ゴシック + 横書き + 西暦)」を切り替える
コード例
public class AbstractFactoryPatternSample {
// 抽象製品
interface DbConnection {
String connect();
}
interface DbStatement {
String executeQuery(String sql);
}
// 抽象ファクトリー
interface DbFactory {
DbConnection createConnection();
DbStatement createStatement();
}
// 具象製品(Java 17: record で簡潔に定義)
record MySqlConnection() implements DbConnection {
@Override
public String connect() {
return "MySQL に接続(jdbc:mysql://localhost:3306/mydb)";
}
}
record MySqlStatement() implements DbStatement {
@Override
public String executeQuery(String sql) {
return "MySQL で実行: " + sql;
}
}
record PostgreSqlConnection() implements DbConnection {
@Override
public String connect() {
return "PostgreSQL に接続(jdbc:postgresql://localhost:5432/mydb)";
}
}
record PostgreSqlStatement() implements DbStatement {
@Override
public String executeQuery(String sql) {
return "PostgreSQL で実行: " + sql;
}
}
// 具象ファクトリー
static class MySqlFactory implements DbFactory {
@Override
public DbConnection createConnection() { return new MySqlConnection(); }
@Override
public DbStatement createStatement() { return new MySqlStatement(); }
}
static class PostgreSqlFactory implements DbFactory {
@Override
public DbConnection createConnection() { return new PostgreSqlConnection(); }
@Override
public DbStatement createStatement() { return new PostgreSqlStatement(); }
}
// クライアント: ファクトリーだけに依存
static void runDbOperation(DbFactory factory) {
var conn = factory.createConnection();
var stmt = factory.createStatement();
System.out.println(conn.connect());
System.out.println(stmt.executeQuery("SELECT * FROM users"));
}
public static void main(String[] args) {
System.out.println("=== MySQL ===");
runDbOperation(new MySqlFactory());
System.out.println("\n=== PostgreSQL ===");
runDbOperation(new PostgreSqlFactory());
}
}Version Coverage
record で具象製品を定義すると、コンストラクタ・getter・equals・toString が自動生成される。var との併用でクライアントコードも簡潔。
// Java 17: record で製品を簡潔に定義
record MySqlConnection() implements DbConnection {
@Override
public String connect() {
return "MySQL に接続";
}
}
// var で型推論
var conn = factory.createConnection();Library Comparison
注意点
新しい Product の種類を追加すると、すべての具象ファクトリーにメソッドを追加する必要がある。Product の種類が頻繁に変わる場合は設計の見直しを検討する
Factory Method で十分な場面に Abstract Factory を適用すると、インターフェースとクラスの数が不要に増える。関連する Product が2つ以上あるかどうかが判断基準
具象ファクトリーの選択ロジック自体を Factory Method や設定ファイルで切り替えるケースが多い。ファクトリーの生成方法も設計に含めること
FAQ
Factory Method が基本です。1種類の Product の生成委譲を理解してから、複数 Product をまとめる Abstract Factory に進むとスムーズです。
設定ファイルや環境変数で具象ファクトリーのクラス名を指定し、リフレクションやマップで切り替えるのが一般的です。DI コンテナを使うプロジェクトではプロファイルで管理します。
Product が1つなら Factory Method で十分です。Abstract Factory は関連する複数の Product を一貫して生成する必要がある場合に使います。