Observer Design Pattern explained with a Python sample

This post shows how the Observer Design Pattern is used to notify all objects that are registered/attached/added to the same type of observer

Introduction

 
What is an Observer Design Pattern?
 
The Observer Design Pattern is a Behavioral Pattern used to notify all objects that are registered/attached/added to the same type of observer.
 
Why use the Observer Design Pattern?
 
It is useful when there is a requirement of "Single object change in its state/behavior/Value needs to notify all other objects which are observing the same object".
 
Basically, a single object should notify multiple objects of the same observer type. It's the relation of one object to many others.
 
Players in this pattern,
  • Subject: Provides a contract to add/remove observers
  • ConcreteSubject: Implements a contract defined by Subject
  • Observer: Provides a contract for updating objects when there is a change in the subject state/behavior/Value
  • ConcreteObserver: Implements a contract defined by Observer 
Problem definition
 
Design a software solution for a wholesale pen seller. This wholesale pen seller will sell pens to shops. When there is a change in pen price per market demand, it should automatically notify the change in pen price to all shops.
 
The players are:
  • Subject – PenSubject
  • ConcreteSubject – Pen
  • Observer – ShopObserver
  • ConcreteObserver – Shop
Below is the PenSubject abstract class which will define contact for ConcreteSubjects, add the below code in subject.py file
  1. from abc import ABC, abstractmethod  
  2.   
  3. class PenSubject(ABC):  
  4.  
  5.     @abstractmethod  
  6.     def add(self, shop):  
  7.         pass  
  8.  
  9.     @abstractmethod  
  10.     def remove(self, shop):  
  11.         pass  
  12.  
  13.     @abstractmethod  
  14.     def notify(self):  
  15.         pass  
Below is the Pen class which implements PenSubject abstract class to add/remove observers and call Notify, which will invoke when there is a change in pen price, add the below code in ConcreteSubject.py file
  1. from subject import PenSubject  
  2.   
  3.   
  4. class Pen(PenSubject):  
  5.   
  6.     def __init__(self, prize):  
  7.         self._penPrize = prize  
  8.   
  9.     shops = []  
  10.   
  11.     def add(self, shop):  
  12.         self.shops.append(shop)  
  13.   
  14.     def remove(self, shop):  
  15.         self.shops.append(shop)  
  16.   
  17.     def notify(self):  
  18.         for shop in self.shops:  
  19.             shop.update(self)  
  20.         print('---------------------------------------')  
  21.  
  22.     @property  
  23.     def penPrize(self):  
  24.         return self._penPrize  
  25.  
  26.     @penPrize.setter  
  27.     def penPrize(self, prize):  
  28.         self._penPrize = prize  
  29.         self.notify()  
Below is the ShopObserver (Observer) abstract class which defines a contract for ConcreteObserver (i.e. in our case Shop), add the below code in observer.py file
  1. from abc import ABC, abstractmethod  
  2.   
  3.   
  4. class ShopObserver(ABC):  
  5.  
  6.     @abstractmethod  
  7.     def update(self, pen):  
  8.         pass  
Below is the Shop class which implements ShopObserver to update the Subject object, add the below code in ConcreteObserver.py file
  1. from observer import ShopObserver  
  2. from ConcreteSubject import Pen  
  3.   
  4.   
  5. class Shop(ShopObserver):  
  6.   
  7.     def __init__(self, shopName: str):  
  8.         self._shopName = shopName  
  9.   
  10.     def update(self, pen: Pen):  
  11.         print("pen prize changed to ", pen.penPrize, ' in 'self._shopName)  
We will see the execution and result now. Add code in startup.py file and run
  1. from ConcreteObserver import Shop  
  2. from ConcreteSubject import Pen  
  3.   
  4. pen = Pen(10)  
  5. pen.add(Shop('Shop1'))  
  6. pen.add(Shop('Shop2'))  
  7. pen.add(Shop('Shop3'))  
  8.   
  9. pen.penPrize = 15  
  10. pen.penPrize = 20  
  11. pen.penPrize = 32  
Below is the result screenshot. In it, we can see that change in pen price value has notified all shops
 
 

Summary

 
In this article, we learned through a code example what the Observer design pattern is, as well as why and where to use it.