Behavioral Pattern

Observer

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Subscribe and get notified.

The Observer pattern is like subscribing to a newsletter: many subscribers (observers) register with a publisher (subject), and whenever the publisher has news, it automatically notifies everyone. The subject doesn't need to know who the subscribers are — just that they want updates.

bad.py
# Problem: subject hard-codes who to notify — closed to new listeners.
class Order:
    def complete(self):
        self.status = "done"
        EmailService().send(self.user, "done")
        Analytics().track("order_done")
        # Inventory? Slack? Edit this method every time.
good.py
# Fix: Observer — subject notifies a list of subscribers.
class Order:
    def __init__(self):
        self._observers = []

    def subscribe(self, observer):
        self._observers.append(observer)

    def complete(self):
        self.status = "done"
        for obs in self._observers:
            obs.on_complete(self)         # don't care who they are

class EmailNotifier:
    def on_complete(self, order):
        send_email(order.user, "done")

class AnalyticsListener:
    def on_complete(self, order):
        track("order_done")

order = Order()
order.subscribe(EmailNotifier())
order.subscribe(AnalyticsListener())
order.complete()                          # both get notified

Subject and observers.

Participants: a Subject that maintains a list of observers and offers subscribe/unsubscribe/notify, and Observer objects with an update() method the subject calls on change.

  • Push vs pull — the subject can push data in the notification, or observers can pull what they need from the subject afterward.
  • Loose coupling — the subject knows observers only through an interface.
  • Dynamic — observers can come and go at runtime.

Pitfalls and modern forms.

  • Lapsed listener / memory leaks — observers that forget to unsubscribe are kept alive by the subject; use weak references or explicit teardown.
  • Ordering & cascades — notification order is usually undefined, and updates can trigger further updates (cycles), risking storms or infinite loops.
  • Thread safety — concurrent subscribe/notify needs care; a snapshot of the listener list is common.
  • Modern incarnations — event listeners, pub/sub, reactive streams (RxJS/Reactor), and the deprecated java.util.Observer; reactive libraries add backpressure and composition on top of the basic idea.