DPDesign Pattern Quest
#19 / 23
B振る舞いDIFF

オブザーバー

Observer

YouTubeのチャンネル登録。新しい動画が出たら、登録者全員のスマホに通知が飛ぶ。

Intent · 目的

ある『被観察者(Subject)』の状態が変わったら、それを購読している『観察者(Observer)』全員に自動通知する仕組み。1対多の通知関係を、結合度を保ったまま実現する。

Motivation · 動機

気温センサーが値を更新したら、UIの数字を書き換え、しきい値を超えたらアラートを出し、外部システムにもログを送りたい。センサー側に『UIを更新して、アラートを出して、ログを送って』と全部直書きしたら、新しい関心事が増えるたびにセンサーを修正する羽目になる。Observer なら、センサーは『変わったよ』と一声叫ぶだけ。聞きたい人(UI、アラート、ログ)が勝手に登録して、勝手に動く。チャンネル登録ボタンを押した人にだけ通知が届く ── まさにあの構造。

適用場面

  • 11つのデータ変更に応じて複数の処理を走らせたい場面(UI更新、外部連携、ログ)。
  • 2イベント駆動・パブリッシュ/サブスクライブ的な振る舞いをしたい場合。
  • 3Observer が実行時に増減する場合。

概念図

サンプルコード

type Listener<T> = (value: T) => void;

class Subject<T> {
  private listeners = new Set<Listener<T>>();
  subscribe(fn: Listener<T>){ this.listeners.add(fn); return () => this.listeners.delete(fn); }
  protected notifyAll(value: T){ this.listeners.forEach(fn => fn(value)); }
}

class TemperatureSensor extends Subject<number> {
  set(t: number){ this.notifyAll(t); }
}

const sensor = new TemperatureSensor();
sensor.subscribe(v => console.log("UI:", v));
sensor.subscribe(v => v > 30 && console.log("alert!"));
sensor.set(31.5);
Pros · メリット
  • Subject と Observer が疎結合。Subject は誰が聞いてるか知らないし、知る必要もない。
  • Observer の追加・削除が動的にできる。新しい関心事を後乗せで足せる。
  • イベント駆動・リアクティブな実装に自然に乗る。
Cons · デメリット
  • 通知順が保証されない。順序に依存するコードを書くと地雷。
  • 通知連鎖が予期せぬループを生む(A→B→A→B…)。
  • 登録解除を忘れると幽霊リスナーが残り、メモリリーク・予期せぬ通知の温床に。

関連パターン

⚔ ready to test

理解度を確かめる時間だ

3 問のクイズで、 このパターンを身体に染み込ませよう。

挑戦する →