メインコンテンツまでスキップ

🧩 Observer × Mediator

✅ 組み合わせの意図

  • Observer により、イベント発生と処理の分離を実現
  • Mediator により、通知先の登録・制御を集約

この組み合わせにより、「発信元は何も知らずにイベントを投げる」「通知の流れは中央で制御する」「通知先は必要に応じて後から追加できる」といった柔軟なイベント設計が可能になる。

✅ よく使われるシーン

  • ユーザー登録やフォーム送信後に複数の後処理(メール送信、ログ記録、Slack 通知など)を行いたいとき
  • 処理フローが将来増えたり変更される予定があるとき
  • 発信元と通知先を疎結合に保ちたいとき(テスト容易性・拡張性が求められる場面)

✅ UML クラス図

✅ コード例

// Observer インターフェース
interface Observer {
update(event: string, data: any): void;
}

// Mediator インターフェース
interface Mediator {
notify(sender: string, event: string, data: any): void;
}

// 実際の Mediator
class EventHub implements Mediator {
private observers: Observer[] = [];

addObserver(observer: Observer): void {
this.observers.push(observer);
}

notify(sender: string, event: string, data: any): void {
for (const obs of this.observers) {
obs.update(event, data);
}
}
}

// イベント発生元(Subject)
class UserService {
constructor(private mediator: Mediator) {}

registerUser(name: string): void {
console.log(`Registering user: ${name}`);
this.mediator.notify("UserService", "user_registered", { name });
}
}

// 通知を受け取る Observer
class Mailer implements Observer {
update(event: string, data: any): void {
if (event === "user_registered") {
console.log(`[Mailer] Sending welcome email to ${data.name}`);
}
}
}

class Logger implements Observer {
update(event: string, data: any): void {
console.log(`[Logger] Event: ${event}, Data: ${JSON.stringify(data)}`);
}
}

// 使用例
const mediator = new EventHub();
const mailer = new Mailer();
const logger = new Logger();
mediator.addObserver(mailer);
mediator.addObserver(logger);

const userService = new UserService(mediator);
userService.registerUser("Taro");

✅ 解説

  • Observer により、通知先は update() メソッドで処理を行う
  • Mediatornotify() で通知処理を集中管理
  • UserService はイベント通知を Mediator に依頼するだけで、実際に何が起きるかを知らなくてよい
  • MailerLoggerObserver として登録され、イベントに応じて個別に処理を実行

この設計により、「通知先を外部から自由に追加・削除できる」 という柔軟性と、「通知の流れを中央から制御できる」 という可視性・保守性が得られる。

✅ まとめ

  • Observerイベントの通知対象を疎結合に
  • Mediator通知の流れを中央集約・制御
  • イベント駆動設計において 柔軟性・保守性・拡張性を両立する代表的な組み合わせ