The Observer pattern defines a one-to-many relationship between objects so that when the state of one object changes, all of its dependent objects are notified and updated automatically. Classes to whose events other classes subscribe are called Subjects, and subscribing classes are called Observers.
This pattern is used when:
The pattern operates with four entities:
There are two ways to receive a state change request from a subject:
This example shows the push method of communication.
from abc import ABC, abstractmethod
class AbstractSubject(ABC):
'''AbstractSubject represents abstract base class of subject, that
notifies observer about state changes.
'''
@abstractmethod
def set_state(self, state):
...
@abstractmethod
def attach(self, observer):
...
@abstractmethod
def detach(self, observer):
...
@abstractmethod
def notify(self):
...
class AbstractObserver(ABC):
'''AbstractObserver
'''
@abstractmethod
def update(self, data):
...
class Sensor(AbstractSubject):
def __init__(self):
self.__state = None
self.__observers: map[int, AbstractObserver] = {}
def set_state(self, state):
self.__state = state
def attach(self, observer):
self.__observers[id(observer)] = observer
def detach(self, observer):
del(self.__observers[id(observer)])
def notify(self):
for observer in self.__observers.values():
observer.update(self.__state)
class AlertingObserver(AbstractObserver):
def __init__(self):
...
def update(self, data):
if data > 90:
print(f"Sensor temperature is too high: {data}")
class MonitoringObserver(AbstractObserver):
def __init__(self):
self.__state = None
def _change_state(self, state):
self.__state = state
def update(self, data):
if self.__state == None:
print(f"Got new data: {data}")
self._change_state(data)
else:
print(f"Data changed from {self.__state} to {data}")
self._change_state(data)
def main():
water_temperature = Sensor()
alerting = AlertingObserver()
monitoring = MonitoringObserver()
water_temperature.attach(alerting)
water_temperature.attach(monitoring)
for i in range(30, 120, 10):
water_temperature.set_state(i)
water_temperature.notify()
if __name__ == '__main__':
main()