How the Observer Pattern Works: A Car Analogy
Tags: programming, python, designpatterns, softwareengineering
Published: 2023-11-13 18:43:42

The observer pattern is a behavioral design pattern that establishes a one-to-many relationship between objects, allowing multiple observers to monitor the state of a single object, referred to as the observable. These observers are automatically notified whenever significant events occur in the observable, and the observable maintains a list of its observers, ensuring they stay informed about any changes in its state.

### Understanding Observer Pattern with a Car Example

Let's delve into the concept by considering the instrument panel of a car—the dashboard behind the steering wheel. This panel includes various gauges and lights, providing real-time updates to the driver about the vehicle's status.

Let's explain the definition of Observer pattern:

#### One-to-Many Relationship

The observer pattern defines a one-to-many relationship, where a single observable object has a connection with multiple observer objects. This relationship is evident in various scenarios:

- **Car and Its Components:**
  - *Observable:* The car itself, capable of changing its state (e.g., speed, fuel level, temperature).
  - *Observers:* Various components within the car, such as the gear, fuel gauge, and speedometer, each updating itself based on the changes it observes.

- **Company and Staff Emails:**
  - *Observable:* The company, responsible for sending out emails.
  - *Observers:* Numerous staff members, are automatically notified of any incoming emails.

- **Phone and Its Components:**
  - *Observable:* The phone, with dynamic features like battery level and room brightness.
  - *Observers:* Components like battery level indicator and ambient light sensor, adjust phone brightness automatically.

#### Maintaining a List of Observers

In the observer pattern, the object being observed maintains a list of its observers. This list allows seamless communication between the observable and its observers:

- **Car and Its Components:**
  - *List of Observers:* The car keeps track of components like the fuel gauge and speedometer, which observe its state.

- **Company and Staff Emails:**
  - *List of Observers:* The company maintains a list of staff emails.

- **Phone and Its Components:**
  - *List of Observers:* The phone maintains a list of apps or components, like a power button click counter app.

#### Notifying Observers of State Changes

The crucial aspect of the observer pattern is the automatic notification of observers when the observable's state changes:

- **Company and Staff Emails:**
  - *Notification:* Staff members automatically receive notifications of any new emails from the company.

- **Car and Its Components:**
  - *Notification:* Car components, such as the fuel gauge and speedometer, automatically update themselves in response to car state changes.

- **Phone and Its Components:**
  - *Notification:* The phone adjusts its brightness automatically based on changes in room brightness.

How it works? Let's demonstrate this in code:

```python
# Define the Car class as the observable
class Car:
    def __init__(self):
        # The observable maintains a list of observers which means it has a relationship with these observers
        self._observers: list = []
        self._fuel_level: int = 4 # (in litres)
        self._speed: int = 0

        # An observer can subscribe to the list
    def add(self, observer) -> None:
        self._observers.append(observer)

        # An observer can also unsubscribe from the list
    def remove(self, observer) -> None:
        self._observers.remove(observer)

        # All subscribed observers are notified whenever this method is invoked
    def notify_observers(self) -> None:
        for observer in self._observers:
            observer.update(self)

        # This accelerate method causes a change in the Car's state and it automatically notifies the observers of its changes
    def accelerate(self) -> None:
        self._speed += 1
        notify_observers()

        # This top_up method also causes a change in the Car's state and it automatically notifies the observers of its changes
    def top_up(self, litre) -> None:
        self._fuel_level += litre
        notify_observers()

        # The below methods return the value in fuel_level and speed respectively
    def get_fuel_level(self) -> int:
        return self._fuel_level

    def get_speed(self) -> int:
        return self._speed

```


`IObserver` defines a signature for all observers to implement

```python
from abc import ABC, abstractmethod

# Define the Observer interface
class IObserver(abc.ABC):

    @abstractmmethod
    def update(self):
        pass
```


Let's define concrete observers

```python
# Define concrete observers

class FuelGauge(IObserver):
    def __init__(self, car):
        self._fuel_level = 0
        self.car = car

    def update(self, car) -> None:
        self._fuel_level = car.get_fuel_level()

class Speedometer(IObserver) :
    def __init__(self, car):
        self._speed = 0
        self.car = car

    def update(self, car) -> None:
        self._speed =car.get_speed()

```


Client class

```python

if __name__ == 'main' : 
    # Create a car object
    car = Car()

    # Create speedometer and fuelGuage objects 
    speedometer: Speedometer = Speedometer(car)
    fuel_guage: FuelGauge = FuelGauge(car)

    # Add the observers to car object
    car.add(speedometer)
    car.add(fuel_gauge)

    # Change the car's state, observers are notified automatically about this change
    car.accelerate()
```


### Conclusion

In summary, the observer pattern facilitates a flexible and decoupled design, allowing objects to communicate without being tightly bound. By exploring the observer pattern through the example of a car, we gain insights into how observables and observers collaborate in a dynamic and efficient manner.

Follow on LinkedIn and Twitter for more  on Design patterns:
[click to follow on LinkedIn](https://www.linkedin.com/in/sherifawofiranye)
[click to follow on Twitter](https://twitter.com/AwofiranyeSher2)