Observer Pattern
The Observer is a behavioral design pattern that defines a one-to-many dependency between objects: when one object (subject) changes state, all its dependents (observers) are notified and updated automatically. It promotes loose coupling by allowing observers to subscribe/unsubscribe dynamically, without the subject knowing their details.
Key Principles
- Publish-Subscribe: Subject publishes changes; observers subscribe.
- Loose Coupling: Subject unaware of observer implementations.
- Dynamic: Observers can attach/detach at runtime.
Structure
- Subject: Maintains observer list; methods:
attach(),detach(),notify(). - Concrete Subject: Tracks state; calls notify on change.
- Observer: Interface with
update()method. - Concrete Observer: Implements update; reacts to notifications.
Python Example: News Publisher (Subject-Observer)
from abc import ABC, abstractmethod
from typing import List
# Observer Interface
class Observer(ABC):
@abstractmethod
def update(self, message: str):
pass
# Concrete Observers
class EmailObserver(Observer):
def __init__(self, email: str):
self.email = email
def update(self, message: str):
print(f"Sending email to {self.email}: {message}")
class SMSObserver(Observer):
def __init__(self, phone: str):
self.phone = phone
def update(self, message: str):
print(f"Sending SMS to {self.phone}: {message}")
# Subject
class NewsPublisher:
def __init__(self):
self._observers: List[Observer] = []
self._message = None
def attach(self, observer: Observer):
self._observers.append(observer)
def detach(self, observer: Observer):
self._observers = [obs for obs in self._observers if obs != observer]
def notify(self):
for observer in self._observers:
observer.update(self._message)
def set_message(self, message: str):
self._message = message
self.notify() # Auto-notify on change
# Usage (Client Code)
if __name__ == "__main__":
publisher = NewsPublisher()
email_obs = EmailObserver("alice@example.com")
sms_obs = SMSObserver("+1234567890")
publisher.attach(email_obs)
publisher.attach(sms_obs)
publisher.set_message("Breaking news: Python 3.13 released!") # Triggers notifications
publisher.detach(email_obs)
publisher.set_message("Update: New features added!") # Only SMS notified
Output:
Sending email to alice@example.com: Breaking news: Python 3.13 released!
Sending SMS to +1234567890: Breaking news: Python 3.13 released!
Sending SMS to +1234567890: Update: New features added!
When to Use Observer
- Event-Driven Systems: UI updates, pub-sub (e.g., MVC models).
- Dynamic Notifications: Subscribe/unsubscribe at runtime.
- Avoid: If few observers or tight coupling needed.
Summary: Observer enables automatic notifications from subject to multiple observers on state changes, fostering decoupled, event-based designs.