Observer Pattern: One-to-Many Dependency, State Notification

The Observer Pattern is a behavioral pattern that defines a one-to-many dependency relationship, in which changing the state of an object automatically notifies all objects depending on it. In the Observer Pattern, the subject maintains a list of observers to store all observer objects that depend on it.

When the state of the subject changes, the subject notifies all observer objects sequentially and calls their update methods. Upon receiving the notification, each observer object automatically updates its own state to remain consistent with the state of the subject.

The implementation of the Observer Pattern typically includes the following roles:

  1. Abstract Subject Class (Subject): Defines an abstract interface used to maintain the observer list and notify observer objects.
  2. Concrete Subject Class (Concrete Subject): Implements the interface of the Abstract Subject class, maintaining an observer list and notifying observers when the state changes.
  3. Abstract Observer Class (Observer): Defines an abstract interface used to update its own state.
  4. Concrete Observer Class (Concrete Observer): Implements the interface of the Abstract Observer class, receiving notifications from the subject and updating its own state.

The core idea of the Observer Pattern is to define a one-to-many dependency relationship; when the state of the subject changes, all observer objects depending on it are notified and automatically updated. The Observer Pattern is suitable for the following scenarios:

  1. To implement loose coupling between objects, facilitating interaction and maintenance.
  2. To notify other objects when an object's state changes, enabling collaboration and coordination.

The Observer Pattern makes a system more flexible and extensible because it abstracts the dependency relationship between objects into interfaces, allowing observer objects to be easily added, removed, or replaced. Additionally, the Observer Pattern can implement an event-driven mechanism, as events can be triggered when the state of the subject changes. However, the Observer Pattern may lead to decreased system performance, as all observer objects must be notified every time the state changes.

# Example implementation structure for the Observer Pattern

class Subject:
    def __init__(self):
        self._observers = []
    
    def attach(self, observer):
        """Adds an observer to the list."""
        if observer not in self._observers:
            self._observers.append(observer)
    
    def detach(self, observer):
        """Removes an observer from the list."""
        self._observers.remove(observer)
    
    def notify(self, event=None):
        """Notifies all registered observers of a state change."""
        for observer in self._observers:
            observer.update(event)

class ConcreteSubject(Subject):
    def __init__(self):
        super().__init__()
        self._state = 0
    
    def set_state(self, value):
        """Sets the state and notifies observers if it changes."""
        old_state = self._state
        self._state = value
        if old_state != self._state:
            self.notify("State changed")

class Observer:
    def __init__(self, name):
        self.name = name
    
    def update(self, event):
        """Updates the observer's state based on the event."""
        print(f"{self.name} received notification: {event}")
        # Logic to update internal state here

class ConcreteObserver(Observer):
    def __init__(self, subject, name):
        super().__init__(name)
        self._subject = subject
        self._subject.attach(self)
    
    def update(self, event):
        # Specific logic for this concrete observer
        print(f"{self.name} is updating based on {event}")