π§© Observer Pattern
β Intentβ
- Allow an object to emit events without knowing who will react to them
- Enable easy modification and extension by simply adding new listeners
β Motivationβ
- Notification targets can be added or replaced dynamically
- Separate each concern into its own class, improving testability and reusability
β When to Useβ
- When you want to decouple event emission from its handling logic
- When the number of notification handlers may increase over time
β Code Exampleβ
- TypeScript
- PHP
- Python
// Observer γ€γ³γΏγΌγγ§γΌγΉ
interface Observer {
update(email: string): void;
}
// ConcreteObserver
class Mailer implements Observer {
update(email: string): void {
console.log(`ιδΏ‘γγΎγγ: ${email} β γγγγοΌ`);
}
}
// SubjectοΌιη₯ε
οΌ
class UserService {
private observers: Observer[] = [];
addObserver(observer: Observer): void {
this.observers.push(observer);
}
notifyObservers(email: string): void {
this.observers.forEach((observer) => observer.update(email));
}
registerUser(email: string): void {
console.log(`γ¦γΌγΆγΌη»ι²: ${email}`);
this.notifyObservers(email);
}
}
// ε©η¨δΎ
const service = new UserService();
service.addObserver(new Mailer());
service.registerUser("user@example.com");
<?php
interface Observer {
public function update(string $email): void;
}
class Mailer implements Observer {
public function update(string $email): void {
echo "ιδΏ‘γγΎγγ: {$email} β γγγγοΌ\n";
}
}
class UserService {
/** @var Observer[] */
private array $observers = [];
public function addObserver(Observer $observer): void {
$this->observers[] = $observer;
}
private function notifyObservers(string $email): void {
foreach ($this->observers as $observer) {
$observer->update($email);
}
}
public function registerUser(string $email): void {
echo "γ¦γΌγΆγΌη»ι²: {$email}\n";
$this->notifyObservers($email);
}
}
// ε©η¨δΎ
$service = new UserService();
$service->addObserver(new Mailer());
$service->registerUser("user@example.com");
from abc import ABC, abstractmethod
class Observer(ABC):
@abstractmethod
def update(self, email: str):
pass
class Mailer(Observer):
def update(self, email: str):
print(f"ιδΏ‘γγΎγγ: {email} β γγγγοΌ")
class UserService:
def __init__(self):
self._observers: list[Observer] = []
def add_observer(self, observer: Observer):
self._observers.append(observer)
def _notify_observers(self, email: str):
for observer in self._observers:
observer.update(email)
def register_user(self, email: str):
print(f"γ¦γΌγΆγΌη»ι²: {email}")
self._notify_observers(email)
# ε©η¨δΎ
service = UserService()
service.add_observer(Mailer())
service.register_user("user@example.com")
β Explanationβ
This code applies the Observer
pattern to design a system where UserService
(the subject)
notifies multiple Observer
instances (subscribers) of an event.
The Observer
pattern defines a one-to-many dependency between objects so that
when one object changes state, all its dependents are notified automatically.
1. Overview of the Observer Patternβ
-
Subject: Maintains a list of observers and notifies them of events
- Represented by
UserService
in this code
- Represented by
-
Observer: Interface for all objects that want to receive notifications
- Represented by
Observer
- Represented by
-
ConcreteObserver: Implements the
Observer
interface and defines custom handling logic- Represented by
Mailer
- Represented by
2. Key Classes and Their Rolesβ
-
Observer
- Common interface for subscribers
- Declares the method
update(email: string): void
-
Mailer
- A concrete observer that implements
Observer
- Implements
update
to send an email notification
- A concrete observer that implements
-
UserService
- The subject that emits notifications
- Has
addObserver
to register observers - Uses
notifyObservers
to notify all registered observers - Executes
registerUser
, which triggers the notification process
3. UML Class Diagramβ
4. Benefits of the Observer Patternβ
- Loose Coupling: Subjects and observers are loosely coupled; adding/removing observers does not impact the subject
- Extensibility: New observers can be added by simply implementing the
Observer
interface - Real-Time Notifications: Allows real-time propagation of state changes
This design is highly effective in event-driven architectures,
especially when multiple objects need to be notified of a single change in state.
It enhances both maintainability and scalability of the codebase.