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.
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.
- 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.
Subject interface: Have
deregister() method to add or remove the Observer(s).
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.