knowledge/technology/dev/programming/patterns/behavioral/Observer Patterns.md
2024-01-17 09:00:45 +01:00

3.8 KiB

obj
concept

Observer Pattern

Description:

The Observer Pattern is a behavioral design pattern that defines a one-to-many dependency between objects so that when one object (the subject) changes state, all its dependents (observers) are notified and updated automatically. It's used to establish dynamic, distributed, and loosely coupled communication between objects, making it easy to maintain consistency and synchronization.

How it's Used:

  1. Subject Interface: Define a subject interface or abstract class that declares methods for attaching, detaching, and notifying observers. It should also have a method to update its state.
  2. Concrete Subject: Create a concrete subject class that implements the subject interface. This class maintains a list of its observers and notifies them when its state changes.
  3. Observer Interface: Define an observer interface with an update method that subjects will call to notify observers of changes.
  4. Concrete Observer: Create concrete observer classes that implement the observer interface. These classes define how they respond to updates from the subject.
  5. Client Code: In client code, create instances of concrete subjects and observers, attach observers to subjects, and let the system handle the rest of the communication.

Example: Let's create an example of the Observer Pattern in Python to model a simple weather monitoring system where weather stations act as subjects and display panels act as observers.

from abc import ABC, abstractmethod

# Step 1: Subject Interface
class Subject(ABC):
    @abstractmethod
    def attach(self, observer):
        pass

    @abstractmethod
    def detach(self, observer):
        pass

    @abstractmethod
    def notify(self):
        pass

# Step 2: Concrete Subject (WeatherStation)
class WeatherStation(Subject):
    def __init__(self):
        self.observers = []
        self.temperature = 0.0

    def attach(self, observer):
        self.observers.append(observer)

    def detach(self, observer):
        self.observers.remove(observer)

    def notify(self):
        for observer in self.observers:
            observer.update(self.temperature)

    def set_temperature(self, temperature):
        self.temperature = temperature
        self.notify()

# Step 3: Observer Interface
class Observer(ABC):
    @abstractmethod
    def update(self, temperature):
        pass

# Step 4: Concrete Observer (DisplayPanel)
class DisplayPanel(Observer):
    def __init__(self, name):
        self.name = name

    def update(self, temperature):
        print(f"{self.name} Display: Temperature is {temperature}°C")

# Step 5: Client Code
def main():
    weather_station = WeatherStation()

    panel1 = DisplayPanel("Panel 1")
    panel2 = DisplayPanel("Panel 2")

    weather_station.attach(panel1)
    weather_station.attach(panel2)

    weather_station.set_temperature(25.5)
    weather_station.set_temperature(30.0)

if __name__ == "__main__":
    main()

In this Python example, we define a Subject interface (Step 1) with attach, detach, and notify methods. The WeatherStation class (Step 2) implements the subject interface, maintains a list of observers, and notifies them when the temperature changes.

We also define an Observer interface (Step 3) with an update method. The DisplayPanel class (Step 4) implements the observer interface and defines how it responds to updates.

In the main function (Step 5), we create a weather station and two display panels. We attach the display panels to the weather station, and when the weather station's temperature changes, it automatically notifies the attached display panels to update their displays. This allows for real-time synchronization between the weather station and the display panels.