Observer#

The Observer is a behavioral design pattern that allows some objects to notify other objects about changes in their state. The Observer pattern provides a way to subscribe and unsubscribe to and from these notifications for multiple objects.

UML Diagram#

+-------------------+        +-------------------+
|    Subject        |<-------|  ConcreteSubject  |
|-------------------|        |-------------------|
| +attach(observer) |        | +attach(observer) |
| +detach(observer) |        | +detach(observer) |
| +notify()         |        | +notify()         |
+-------------------+        +-------------------+
        ^                           ^
        |                           |
+-------------------+        +-------------------+
|    Observer       |        |  ConcreteObserver |
|-------------------|        |-------------------|
| +update(state)    |        | +update(state)    |
+-------------------+        +-------------------+

In this diagram, Subject is an interface with methods attach(observer), detach(observer), and notify(). Observer is an interface with the method update(state). ConcreteSubject and ConcreteObserver are classes that implement the Subject and Observer interfaces, respectively. The arrows indicate that the ConcreteSubject and ConcreteObserver classes inherit from the Subject and Observer interfaces.

Java Example#

import java.util.ArrayList;
import java.util.List;

public interface Observer {
    void update(String state);
}

public interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;

    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }
}

public class ConcreteObserver implements Observer {
    @Override
    public void update(String state) {
        System.out.println("State changed: " + state);
    }
}

Python Example#

from __future__ import annotations
from abc import ABC, abstractmethod

class Observer(ABC):
    @abstractmethod
    def update(self, state: str) -> None:
        pass

class Subject(ABC):
    @abstractmethod
    def attach(self, observer: Observer) -> None:
        pass

    @abstractmethod
    def detach(self, observer: Observer) -> None:
        pass

    @abstractmethod
    def notify(self) -> None:
        pass

class ConcreteSubject(Subject):
    _state: str = None
    _observers: list[Observer] = []

    def attach(self, observer: Observer) -> None:
        self._observers.append(observer)

    def detach(self, observer: Observer) -> None:
        self._observers.remove(observer)

    def notify(self) -> None:
        for observer in self._observers:
            observer.update(self._state)

    def set_state(self, state: str) -> None:
        self._state = state
        self.notify()

class ConcreteObserver(Observer):
    def update(self, state: str) -> None:
        print(f"State changed: {state}")