knowledge/technology/programming/patterns/behavioral/Observer Patterns.md
2023-12-04 11:02:23 +01:00

89 lines
No EOL
3.8 KiB
Markdown

---
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](../../languages/Python.md) to model a simple weather monitoring system where weather stations act as subjects and display panels act as observers.
```python
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](../../languages/Python.md) 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.