🧩 Observer × Mediator
✅ Combination Intent
- Use
Observer
to decouple event emitters from event listeners - Use
Mediator
to centralize control over notification flow
This combination allows you to emit events without knowing who will respond, manage notification targets in one place, and dynamically add/remove observers without modifying the source.
✅ Common Use Cases
- When you need to perform multiple actions (e.g., email, logging, Slack notifications) after user registration or form submission
- When the post-processing steps may change or increase in the future
- When decoupling the sender and listeners improves testability and flexibility
✅ UML Class Diagram
✅ Code Example
- 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")
✅ Explanation
Observer
defines theupdate()
method that responds to eventsMediator
(viaEventHub
) manages how events are broadcast to observersUserService
only callsnotify()
on the mediator, unaware of the actual event handlersMailer
andLogger
areObserver
implementations that respond independently to events
This design enables loose coupling between emitters and listeners, while also allowing centralized and transparent control of notification behavior.
✅ Summary
Observer
enables event-driven design with flexible listenersMediator
centralizes event flow and observer management- Ideal for event-driven systems that require scalability, testability, and modular post-processing