📌

デザインパターンを学ぶ #21 アブストラクトファクトリー(Abstract Factory)

に公開

1. はじめに

今回は Abstract Factory(アブストラクトファクトリー)パターン
目的は、関連するオブジェクト群を「組み合わせ単位」で生成する仕組みをまとめることです。

「同じ系統のオブジェクトを一貫性をもって作りたい」ときに役立ちます。
GUIライブラリで「Windows用の部品」と「Mac用の部品」を切り替える例が典型です。

2. Abstract Factoryとは?

登場する役割は以下の通りです:

  • AbstractFactory … 製品群を生成するインターフェース
  • ConcreteFactory … 実際に製品群を生成する工場
  • AbstractProduct … 製品の抽象インターフェース
  • ConcreteProduct … 具体的な製品
  • Client … 工場を通じて製品群を利用する

ポイントは、**「工場を切り替えるだけで、関連する製品群を一括で差し替えできる」**ことです。

3. 実装イメージ(PHP)

<?php
// Abstract Products
interface Button {
    public function render(): string;
}
interface Checkbox {
    public function check(): string;
}

// Concrete Products (Windows)
class WindowsButton implements Button {
    public function render(): string { return "Windows風ボタン"; }
}
class WindowsCheckbox implements Checkbox {
    public function check(): string { return "Windows風チェックボックス"; }
}

// Concrete Products (Mac)
class MacButton implements Button {
    public function render(): string { return "Mac風ボタン"; }
}
class MacCheckbox implements Checkbox {
    public function check(): string { return "Mac風チェックボックス"; }
}

// Abstract Factory
interface GUIFactory {
    public function createButton(): Button;
    public function createCheckbox(): Checkbox;
}

// Concrete Factories
class WindowsFactory implements GUIFactory {
    public function createButton(): Button { return new WindowsButton(); }
    public function createCheckbox(): Checkbox { return new WindowsCheckbox(); }
}
class MacFactory implements GUIFactory {
    public function createButton(): Button { return new MacButton(); }
    public function createCheckbox(): Checkbox { return new MacCheckbox(); }
}

// Client
class Application {
    private Button $button;
    private Checkbox $checkbox;

    public function __construct(GUIFactory $factory) {
        $this->button = $factory->createButton();
        $this->checkbox = $factory->createCheckbox();
    }

    public function renderUI(): void {
        echo $this->button->render() . PHP_EOL;
        echo $this->checkbox->check() . PHP_EOL;
    }
}

// --- 実行例 ---
$app = new Application(new WindowsFactory());
$app->renderUI();
// Windows風ボタン
// Windows風チェックボックス

$app = new Application(new MacFactory());
$app->renderUI();
// Mac風ボタン
// Mac風チェックボックス

4. メリット・デメリット

メリット

  • 製品群の一貫性を保証できる
  • 工場を切り替えるだけで環境に応じた実装を利用できる
  • 依存を抽象に寄せるのでテストや拡張が容易

デメリット

  • クラスやインターフェースの数が増える
  • 小規模ではオーバーエンジニアリングになりやすい

5. 使いどころ

  • プラットフォームごとにUI部品を変えたいとき(Windows / Mac / Linux)
  • DBドライバや外部サービスの実装を切り替えるとき
  • 製品群の一貫性を守りつつ差し替えたいとき

関連するオブジェクトをまとめて差し替える」のがキーワードです。

Discussion