🧩 Observer × Mediator
✅ 組み合わせの意図
Observer
により、イベント発生と処理の分離を実現Mediator
により、通知先の登録・制御を集約
この組み合わせにより、「発信元は何も知らずにイベントを投げる」「通知の流れは中央で制御する」「通知先は必要に応じて後から追加できる」といった柔軟なイベント設計が可能になる。
✅ よく使われるシーン
- ユーザー登録やフォーム送信後に複数の後処理(メール送信、ログ記録、Slack 通知など)を行いたいとき
- 処理フローが将来増えたり変更される予定があるとき
- 発信元と通知先を疎結合に保ちたいとき(テスト容易性・拡張性が求められる場面)
✅ UML クラス図
✅ コード例
- TypeScript
- PHP
- Python
// 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");
<?php
interface Observer {
public function update(string $event, array $data): void;
}
interface Mediator {
public function notify(string $sender, string $event, array $data): void;
}
class EventHub implements Mediator {
private array $observers = [];
public function addObserver(Observer $observer): void {
$this->observers[] = $observer;
}
public function notify(string $sender, string $event, array $data): void {
foreach ($this->observers as $observer) {
$observer->update($event, $data);
}
}
}
class UserService {
public function __construct(private Mediator $mediator) {}
public function registerUser(string $name): void {
echo "Registering user: {$name}\n";
$this->mediator->notify("UserService", "user_registered", ['name' => $name]);
}
}
class Mailer implements Observer {
public function update(string $event, array $data): void {
if ($event === "user_registered") {
echo "[Mailer] Sending welcome email to {$data['name']}\n";
}
}
}
class Logger implements Observer {
public function update(string $event, array $data): void {
echo "[Logger] Event: {$event}, Data: " . json_encode($data) . "\n";
}
}
// 使用例
$mediator = new EventHub();
$mailer = new Mailer();
$logger = new Logger();
$mediator->addObserver($mailer);
$mediator->addObserver($logger);
$userService = new UserService($mediator);
$userService->registerUser("Taro");
from abc import ABC, abstractmethod
class Observer(ABC):
@abstractmethod
def update(self, event: str, data: dict) -> None:
pass
class Mediator(ABC):
@abstractmethod
def notify(self, sender: str, event: str, data: dict) -> None:
pass
class EventHub(Mediator):
def __init__(self):
self.observers: list[Observer] = []
def add_observer(self, observer: Observer) -> None:
self.observers.append(observer)
def notify(self, sender: str, event: str, data: dict) -> None:
for observer in self.observers:
observer.update(event, data)
class UserService:
def __init__(self, mediator: Mediator):
self.mediator = mediator
def register_user(self, name: str) -> None:
print(f"Registering user: {name}")
self.mediator.notify("UserService", "user_registered", {"name": name})
class Mailer(Observer):
def update(self, event: str, data: dict) -> None:
if event == "user_registered":
print(f"[Mailer] Sending welcome email to {data['name']}")
class Logger(Observer):
def update(self, event: str, data: dict) -> None:
print(f"[Logger] Event: {event}, Data: {data}")
# 使用例
mediator = EventHub()
mailer = Mailer()
logger = Logger()
mediator.add_observer(mailer)
mediator.add_observer(logger)
user_service = UserService(mediator)
user_service.register_user("Taro")
✅ 解説
Observer
により、通知先はupdate()
メソッドで処理を行うMediator
がnotify()
で通知処理を集中管理UserService
はイベント通知をMediator
に依頼するだけで、実際に何が起きるかを知らなくてよいMailer
やLogger
はObserver
として登録され、イベントに応じて個別に処理を実行
この設計により、「通知先を外部から自由に追加・削除できる」 という柔軟性と、「通知の流れを中央から制御できる」 という可視性・保守性が得られる。
✅ まとめ
Observer
で イベントの通知対象を疎結合にMediator
で 通知の流れを中央集約・制御- イベント駆動設計において 柔軟性・保守性・拡張性を両立する代表的な組み合わせ