Menu
Coddy logo textTech

Observerパターン

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

オブザーバーパターンは、オブジェクト間の1対多のリレーションシップを確立します。1つのオブジェクト(サブジェクト)の状態が変化すると、そのすべての依存先(オブザーバー)に自動的に通知されます。これは、UIの更新、イベントシステム、またはアプリケーションの複数の部分が変更に反応する必要があるあらゆるシナリオに最適です。

このパターンには2つの主要な役割があります。オブザーバーのリストを保持して変更を通知するSubjectと、自身を登録して更新に応答するObserversです:

abstract class Observer {
  void update(String message);
}

class NewsAgency {
  final List<Observer> _observers = [];
  String _latestNews = '';

  void subscribe(Observer observer) {
    _observers.add(observer);
  }

  void unsubscribe(Observer observer) {
    _observers.remove(observer);
  }

  void publishNews(String news) {
    _latestNews = news;
    for (var observer in _observers) {
      observer.update(_latestNews);
    }
  }
}

class NewsChannel implements Observer {
  final String name;
  NewsChannel(this.name);

  @override
  void update(String message) {
    print('$name received: $message');
  }
}

void main() {
  var agency = NewsAgency();
  var cnn = NewsChannel('CNN');
  var bbc = NewsChannel('BBC');

  agency.subscribe(cnn);
  agency.subscribe(bbc);

  agency.publishNews('Breaking news!');
  // CNN が受信しました: Breaking news!
  // BBC が受信しました: Breaking news!
}

publishNews が呼び出されると、エージェンシーは購読しているすべてのオブザーバーを反復処理し、それらの update メソッドを呼び出します。オブザーバーはいつでも購読または購読解除ができるため、システムは柔軟で疎結合になります。つまり、サブジェクトはオブザーバーの具体的な型を知る必要がありません。

challenge icon

チャレンジ

簡単

Observer パターンを使用して、株価アラートシステムを構築しましょう!株価ティッカーが価格の変動を複数の投資家に通知し、各投資家が独自の方法で市場の更新に反応できるシステムを作成します。

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

  • stock_system.dart: ここにオブザーバーシステムを作成します:
    • void onPriceChange(String stockName, double price) メソッドを持つ抽象クラス Investor
    • Investor を実装する DayTrader クラス。name フィールドを持ち、その onPriceChange メソッドは次のように出力します:[name] sees [stockName] at $[price] - Making quick trade!
    • Investor を実装する LongTermInvestor クラス。name フィールドを持ち、その onPriceChange メソッドは次のように出力します:[name] notes [stockName] at $[price] - Holding steady.
    • 以下の機能を持つ StockTicker クラス(サブジェクト):
      • String stockName フィールド
      • 購読している投資家を保存するためのプライベートリスト
      • 投資家を追加するための subscribe(Investor investor) メソッド
      • 投資家を削除するための unsubscribe(Investor investor) メソッド
      • すべての購読中の投資家に新しい価格を通知する updatePrice(double newPrice) メソッド
  • main.dart: 株価システムをインポートし、Observer パターンの動作を実演します:
    • DART という名前の銘柄の StockTicker を作成します
    • Alice という名前の DayTrader と、Bob という名前の LongTermInvestor を作成します
    • 両方の投資家をティッカーに登録(subscribe)します
    • 価格を 150.50 に更新します(両方の投資家に通知される必要があります)
    • 空行を出力します
    • Alice の登録を解除(unsubscribe)します
    • 価格を 155.75 に更新します(現在は Bob だけに通知される必要があります)

これは、Observer パターンがいかに疎結合なシステムを作成するかを示しています。StockTicker は、通知先がデイトレーダーなのか長期投資家なのかを知る必要はなく、購読している対象に対して onPriceChange を呼び出すだけです!

期待される出力:

Alice sees DART at $150.5 - Making quick trade!
Bob notes DART at $150.5 - Holding steady.

Bob notes DART at $155.75 - Holding steady.

チートシート

Observer パターンは、サブジェクトの状態が変化したときに、すべてのオブザーバーに通知を行う 1 対多のリレーションシップを確立します。

このパターンには 2 つの主要な役割があります。

  • Subject (サブジェクト): オブザーバーのリストを保持し、変更を通知します
  • Observer (オブザーバー): サブジェクトに登録し、更新に応答します

基本的な実装:

abstract class Observer {
  void update(String message);
}

class Subject {
  final List<Observer> _observers = [];

  void subscribe(Observer observer) {
    _observers.add(observer);
  }

  void unsubscribe(Observer observer) {
    _observers.remove(observer);
  }

  void notifyObservers(String data) {
    for (var observer in _observers) {
      observer.update(data);
    }
  }
}

class ConcreteObserver implements Observer {
  final String name;
  ConcreteObserver(this.name);

  @override
  void update(String message) {
    print('$name received: $message');
  }
}

主な利点:

  • サブジェクトとオブザーバー間の疎結合
  • オブザーバーは動的に購読/購読解除が可能
  • サブジェクトは特定のオブザーバーの型を知る必要がない

自分で試してみよう

import 'stock_system.dart';

void main() {
  // TODO: 'DART'という名前の銘柄のStockTickerを作成してください
  
  // TODO: 'Alice'という名前のDayTraderを作成してください
  
  // TODO: 'Bob'という名前のLongTermInvestorを作成してください
  
  // TODO: 両方の投資家をティッカーに購読させてください
  
  // TODO: 価格を150.50に更新してください(両方の投資家に通知される必要があります)
  
  // TODO: 空行をプリントしてください
  
  // TODO: Aliceのティッカー購読を解除してください
  
  // TODO: 価格を155.75に更新してください(現在はBobのみに通知される必要があります)
}
quiz icon腕試し

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

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