Implementing Newsletter Subscription using Observer Design Pattern in Python

Observer Design Pattern is a design pattern in Python that facilitates a one-to-many relationship. Say, for example, you and several other readers subscribed to a newsletter. When there is a new newsletter available, you will receive it along with other subscribers. Suppose, if you don’t want to receive the newsletter, you can cancel your subscription and you will not receive the new editions.

An observer design pattern is not limited to the newsletter subscription. It can be any information such as a concurrent thread signal, a signal from an operating system, and so on.  An observer design pattern is a form of a publishing-subscriber pattern. It facilitates managing subscriptions and broadcasting information to subscribers.

Benefits of Observer Design Pattern

Observer Design Pattern has a static object called Subject and a variable object called Observers. There can be zero or N number of observers, which can change based on subscription. Here, the Subject keeps the Observers, and if any of the object state changes, the  Subject notifies other Observers. For example, consider the case of a LinkedIn post. When you post a new LinkedIn post (state change), the timeline of your followers is updated with your new post.

 Let’s look into its benefits.

  • Facilitates a loose coupling between Subject and Observers
  • Observers can be updated at runtime
  • A subject can keep zero or N number of observers
  • The aptitude of broadcasting messages between Subject and Observers.

Newsletter Subscription Implementation

Let’s design a simple newsletter subscription model to understand the observer design pattern. As we discussed, an observer design pattern has two main objects – Subject and Observer. The subject can add, remove, and notify the observers through register_observer, unregister_observer, and notify_observer. Whereas, the observer is an interface that has an abstract method – notify.    



Observer Design Pattern

Here, two concrete observers – CompanyNewsletterObserver and ConsumerNewsletterObserver – are derived from the Observer interface. These concrete methods implement the abstract method notify, and the Subject will call the notify method in its notify_observer method. So to send information to the subscribers, we simply need to call the notify_observer method in the Subject. Let’s look into the implementation.

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

import abc
import time
import datetime
  
class Subject(object):
    def __init__(self):
        self.observers = []
        self.cur_time = None
  
    def register_observer(self, observer):
        if observer in self.observers:
            print(observer, 'already registered')
        else:
            self.observers.append(observer)
  
    def unregister_observer(self, observer):
        try:
            self.observers.remove(observer)
        except ValueError:
            print('Cannot Indentify the Observer')
  
    def notify_observer(self):
        self.cur_time = datetime.datetime.now()
          
        for observer in self.observers:
            observer.notify(self.cur_time)
  
class Observer(object, metaclass=abc.ABCMeta):    
    """ Abstract class for Observers """
    @abc.abstractmethod
    def notify(self, unix_timestamp):
        pass
  
  
class CompanyNewsletterObserver(Observer):
    """ Company Newsletter """
    def __init__(self, name):
        self.name = name
  
    def notify(self, time):
        print(self.name, ':', time)
  
class ConsumerNewsletterObserver(Observer):
    """ Consumer Newsletter """
    def __init__(self, name):
        self.name = name
  
    def notify(self, time):
        print(self.name, ':', time)
  
if __name__ == '__main__':
    subject = Subject()
  
    print('Registering company_newsletter_observer')
    cmp_observer = CompanyNewsletterObserver('company_newsletter_observer')
    subject.register_observer(cmp_observer)
    subject.notify_observer()
    print()
    time.sleep(2)
  
    print('Registering consumer_newsletter_observer')
    con_observer = ConsumerNewsletterObserver('consumer_newsletter_observer')
    subject.register_observer(con_observer)
    subject.notify_observer()
    print()
    time.sleep(2)
  
    print('Unregistering company_newsletter_observer')
    subject.unregister_observer(cmp_observer)
    subject.notify_observer()

chevron_right


Output:

Registering company_newsletter_observer
company_newsletter_observer : 2020-10-15 20:40:04.335355

Registering consumer_newsletter_observer
company_newsletter_observer : 2020-10-15 20:40:06.336913
consumer_newsletter_observer : 2020-10-15 20:40:06.336913

Unregistering company_newsletter_observer
consumer_newsletter_observer : 2020-10-15 20:40:08.339662

You can refer to the above output to understand the behavior of code while registering and un-registering observers.

An observer design pattern best suits the need to achieve a one-to-many relationship. You can broadcast the same information to many listeners. And, the listeners can be added or removed at runtime. Here, the subject only has information about the observer’s interface, which helps to maintain loose coupling between the subject and the observers.  

Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.

To begin with, your interview preparations Enhance your Data Structures concepts with the Python DS Course.




My Personal Notes arrow_drop_up

Focused on developing machine learning models and constantly doing research on the complex business challenges to solve problems and deliver valuable insights Expertise includes • Python Programming • Probability and Statistics • Data Modelling and Evaluation • Machine learning algorithms

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :

Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.