Menu
Coddy logo textTech

Observerパターン

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

Observer Patternは、オブジェクト間に一対多の関係を確立する振る舞いデザインパターンです。1つのオブジェクト(subject)の状態が変化すると、そのすべての依存オブジェクト(observers)に自動的に通知され、更新されます。

newsletter の購読について考えてみましょう。newsletter は subject であり、購読者は observer です。新しい号が発行されると、newsletter は各購読者の詳細を知る必要なく、すべての購読者が自動的にそれを受け取ります。

PHPでの基本的な実装例を次に示します:

<?php
interface Observer {
    public function update(string $message): void;
}

class Newsletter {
    private array $subscribers = [];
    
    public function subscribe(Observer $observer): void {
        $this->subscribers[] = $observer;
    }
    
    public function publish(string $content): void {
        foreach ($this->subscribers as $subscriber) {
            $subscriber->update($content);
        }
    }
}

class EmailSubscriber implements Observer {
    public function __construct(private string $email) {}
    
    public function update(string $message): void {
        echo "Sending to {$this->email}: $message\n";
    }
}

$newsletter = new Newsletter();
$newsletter->subscribe(new EmailSubscriber("alice@example.com"));
$newsletter->subscribe(new EmailSubscriber("bob@example.com"));
$newsletter->publish("New article released!");

出力:

Sending to alice@example.com: New article released!
Sending to bob@example.com: New article released!

このパターンは、subjectとそのobserversを分離します。Newsletterクラスは、emailの購読者、SMSの購読者、またはプッシュ通知サービスのいずれに通知しているのかを知る必要がありません。Observerインターフェースをimplementsする対象に対して、単にupdate()を呼び出します。これにより、既存のコードを変更せずに新しいobserverの種類を簡単に追加できます。

challenge icon

チャレンジ

簡単

Observer Pattern を使用して株価アラートシステムを構築しましょう。株価が変化すると、登録されているすべての Investors に自動的に通知されます。これは、このパターンの現実世界における完璧な適用例です。

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

  • Observer.php:単一のメソッド update(string $stockName, float $price): void を持つ Observer interface を Define します。これは、notifications を受け取るためにすべての observers が従う必要がある契約です。
  • Investors.php:Observer ファイルを Include し、interface を implements する2つの class を Create します。
    • EmailInvestor:constructor で email address を受け取ります(constructor promotion を使用します)。その update() method は "Email to [email]: [stockName] is now $[price]" を出力します。
    • SmsInvestor:constructor で phone number を受け取ります。その update() method は "SMS to [phone]: [stockName] is now $[price]" を出力します。
  • Stock.php:Observer ファイルを Include し、subject として acts する Stock class を Create します。Stock は次のようにします。
    • stock name と current price を保存します(name には constructor promotion を使用し、price を 0.0 に Initialize します)
    • observers の private array を Maintain します
    • observers を追加する subscribe(Observer $observer): void method を持たせます
    • price を更新し、すべての observers に notify する setPrice(float $price): void method を持たせます
    observers に Notifying するときは、各 observer の update() method を stock name と new price とともに Call します。
  • main.php:Investors ファイルと Stock ファイルを Include します。3つの inputs、つまり stock name、email address、phone number を受け取ります。

    given name で Stock を Create します。email address を持つ EmailInvestor と、phone number を持つ SmsInvestor を subscribe します。

    すべての subscribers への notifications を trigger するため、stock price を 150.50 に設定します。

Observer Pattern により、Stock class は具体的な notification methods から decoupled になります。Stock class をまったく変更せずに、後から簡単に PushInvestorSlackInvestor を追加できます。

自分で試してみよう

<?php
require_once 'Investors.php';
require_once 'Stock.php';

// 入力を読み取る
$stockName = trim(fgets(STDIN));
$email = trim(fgets(STDIN));
$phone = trim(fgets(STDIN));

// TODO: 指定された名前でStockを作成する

// TODO: メールアドレスでEmailInvestorを購読する

// TODO: 電話番号でSmsInvestorを購読する

// TODO: 株価を150.50に設定して通知をトリガーする
?>
quiz icon腕試し

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

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

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