Menu
Coddy logo textTech

Factoryパターン

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 72/91。

Factory Patternは、オブジェクトの作成を別のクラスまたはmethodに委譲する生成デザインパターンです。コード全体でnewを直接使用する代わりに、factoryにオブジェクトの作成を依頼します。

このパターンは、共通の interface を共有する複数の関連クラスがあり、ある条件に基づいてどのクラスをインスタンス化するか決定したい場合に特に役立ちます。異なるチャネルを介してメッセージを send できる notification システムを考えてみましょう。

<?php
interface Notification {
    public function send(string $message): string;
}

class EmailNotification implements Notification {
    public function send(string $message): string {
        return "Email: $message";
    }
}

class SmsNotification implements Notification {
    public function send(string $message): string {
        return "SMS: $message";
    }
}

factory がなければ、あちこちに if 文や new の呼び出しを散在させることになります。factory はこのロジックを一元化します。

<?php
class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException("Unknown type: $type")
        };
    }
}

$notification = NotificationFactory::create('email');
echo $notification->send('Hello!');

出力:

Email: Hello!

主なbenefitは、コードが具象クラスではなくNotification interfaceに依存することです。後からPushNotificationクラスを追加する場合は、factoryだけを更新すれば済みます。factoryを使用するすべてのコードは、変更なしで新しい型に自動的にアクセスできるようになります。

challenge icon

チャレンジ

簡単

Factory Pattern を使用して Document generator system を構築しましょう。異なる document type(PDF、HTML、Plain Text)は共通の interface を共有しながら異なる Output を生成します。これは、object の作成を factory に一元化するのに最適なシナリオです。

コードを4つのファイルに整理します。

  • Document.php:すべての document type が従うべき契約を定義する Document interface を Create します。content を受け取り、formatted な document Output を return する単一の render(string $content): string method を持つ should があります。
  • Documents.php:Document interface を含め、それを実装する3つの class を Create します。
    • PdfDocument:その render() method は "PDF: [content]" を return します
    • HtmlDocument:その render() method は "<html>[content]</html>" を return します
    • TextDocument:その render() method は "TXT: [content]" を return します
  • DocumentFactory.php:Documents file を含め、static method create(string $type): Document を持つ DocumentFactory class を Create します。この method は match を使用して、type に基づき appropriate な document object を return する should があります。
    • "pdf" は新しい PdfDocument を return します
    • "html" は新しい HtmlDocument を return します
    • "text" は新しい TextDocument を return します
    • その他の type では、message "Unknown document type: [type]" を持つ InvalidArgumentException を throw する should があります
  • main.php:DocumentFactory file を含めます。document type と render する content の2つの入力を受け取ります。

    factory を使用して appropriate な document type を Create し、その後 content とともに render() method を Call して result を print します。

    新しい line で、なぜこの pattern が valuable なのかを示すために "Factory benefit: Adding new types only requires updating the factory" を print します。

Factory Pattern によりコードの柔軟性が保たれます。後から MarkdownDocument を追加する必要がある場合も、既存のコードが変更されずに動作し続ける中で、factory だけを更新すればよいのです。

自分で試してみよう

<?php
require_once 'DocumentFactory.php';

// 入力を読み取る
$type = trim(fgets(STDIN));
$content = trim(fgets(STDIN));

// TODO: DocumentFactoryを使用して適切なドキュメントタイプを作成する
// TODO: contentを指定してrender()メソッドを呼び出し、結果を出力する
// TODO: On a new line, print "Factory benefit: Adding new types only requires updating the factory"

?>
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: PHPオンラインコンパイラ