×

Observer Design Pattern with Python

Observer Design Patterns Python Feature

There will be cases where the interface needs to be informed about whether a certain event or operation occurred on a certain object or not, in an application.

Interfaces wish to be informed about the occurrence of events or operations because sometimes the interface may require to trigger specific action(s) depending upon the operation performed on any object of the system.

This is where Observer Design Pattern comes into the picture. Observer Pattern suggests defining interface(i.e Observer) which will be informed every time any event occurs in the system.

So, in a system, there will be two types of entities:

  • Observer: Entities who wishes to be informed about the occurrence of any event.
  • Observable: Entities that will inform the Observer if any operation performed on them.

For each operation, there will be a separate Observer in the system.

Real-life example

We use Facebook, Instagram, and Snapchat, etc. On any of the social media platforms as soon as we post any picture, short video, or anything, all our friends and followers get notified.

So, in the social media application, there is an interface–U1 that facilitates posts to be uploaded and there is a separate interface–U2 that sends a notification to all friends and followers — if U2 gets informed by U1.

Cleary, U2-interface needs to be informed by interface-U1 and they serve as Observer and Observable respectively.

Key Point

  • Subject: Interface for observers to register and unregister themselves in the system.

The Subject knows which observer to be notified of when an event occurs. And also stores the information that gets changed with the occurrence of the event.

  • Multiple observers may need to get notified for operation or event in one common object.
  • Subject just sends the notification saying that any operation or event has been occured, but it does not pass any information.
  • When get notified Observer has to ask Subject interface for the information that gets changed.

Implementation

Subject interface: Have register() and deregister() method to add or remove the Observer(s).

  • Have notify() method in order to send notiifcation to Observers.
  • And have, subject_state() setter and a property method, to store and return the information respectively.
class Subject:
    def __init__(self):
        self._observers = set()
        self._subject_state = None

    def register(self, observer):
        observer._subject = self
        self._observers.add(observer)

    def deregister(self, observer):
        observer._subject = None
        self._observers.remove(observer)

    def _notify(self):
        for observer in self._observers:
            observer.update(self._subject_state)

    @property
    def subject_state(self):
        return self._subject_state

    @subject_state.setter
    def subject_state(self, arg):
        self._subject_state = arg
        self._notify()
  • The abstract observer Interface and the concrete Observer interface.
class Observer():
    def __init__(self):
        self._subject = None
        self._observer_state = None

    @abstractmethod
    def update(self, arg):
        pass
class ConcreteObserver(Observer):
    def update(self, arg):
        self._observer_state = arg
        # ...
  • The Driver code
def main():
    subject = Subject()
    concrete_observer = ConcreteObserver()
    subject.register(concrete_observer)
    subject.subject_state = 123


if __name__ == "__main__":
    main()

With this article, we can conclude that — Observer Pattern ensures that when an object is altered, it will lead to a cascade of changes to be applied to the dependent interface’s objects.