Python Design Patterns - Observer Pattern


Let's understand behavioural design pattern before we start on observer pattern.

Behavioural design pattern

This type of design patterns will help you to solve problems related to behaviour of your program. This pattens are concerned about interactivity between objects and the responsibility of objects and yet they must be loosely coupled to each other.

Observer pattern is one of this type of design pattern which we will understand in this story.

Observer pattern

In this design pattern, The object maintains the list of observers which are dependent on it. So whenever something gets changed in that object, it will notify to all observers in the list. That object is also called as subject very often. 

Known Example -

Email Service is a best example for Observer pattern. Whenever new feature comes in to the application, email service notifies to all subscribers by sending email about new feature information. So here subscribers are observers and application feature is a subject. Whenever any feature is added or modified, email service notifies.

Observer pattern implementation

Here we will write python program in which we will understand how we can implement observer pattern in python. Let's take an example of blog writer.

We will have two important variable 1) subscribers (observers) 2) articles (subject).

Each instance of BlogWriter can have his/her own subscribers and articles. So let's write and understand the implementation.

'''
Obeserver Design pattern
'''

class User:
    '''
    User class will act role of observer to subject
    '''
    def __init__(self, name):
        self.name = name

    def update(self, article, blog_writer):
        print(f'For {self.name}, new article by {blog_writer.name} is added')

class BlogWriter:
    '''
    BlogWriter class is useful to blog writer to add new article
    and manage subscribers as well
    '''
    def __init__(self, name):
        self.name = name
        self.__subscribers = []
        self.__articles = []

    def add_article(self, article):
        '''
        Add new article and notify subscribers
        '''
        self.__articles.append(article)
        self.notify_subscribers(article)

    def get_articles(self):
        '''
        Get articles written by {self}
        '''
        return self.__articles

    def subscribe(self, subscriber):
        '''
        Add new subscriber to notify on adding article
        '''
        self.__subscribers.append(subscriber)

    def unsubscribe(self, subscriber):
        '''
        User can unsubscribe from further notifications
        '''
        return self.__subscribers.remove(subscriber)

    def subscribers(self):
        '''
        Get subsribers
        '''
        return self.__subscribers

    def notify_subscribers(self, article):
        '''
        Notifying all the subsribers about new addition of an article
        '''
        for sub in self.__subscribers:
            sub.update(article, self)

if __name__ == '__main__':
    blog_writer = BlogWriter('Hardik\'s blog')
    shailaja = User('Shailaja')
    aarav = User('Aarav')
    blog_writer.subscribe(shailaja)
    blog_writer.subscribe(aarav)
    blog_writer.add_article('Article 1')

As you can see in above example, BlogWriter class is for different blog writers where they allow users to subscribe and get articles. Subscribers will be observers to particular blog writer and article is the subject for those subscribers. Each blog writer can have their own set of subscribers and articles

Further, User class is used to create users and those users can subscribe specific blog writer and will get notified whenever new article will be added by that blog writer.

There are two strategies to implement this pattern, 1) Pull 2) Push.

Above example has implemented push strategy. Whenever new article is added user will get notified by writer.  However in pull strategy, user tries to know frequently whether a new article is added or not. Frequency can be set as per the requirement in the problem.

Benefits

  • Any kind of subscriber can be added irrespective of the type of subscriber as far as subscriber class has implemented specific listening method. (update method in our User class in above example)
  • Subject doesn't need to know what observer does after knowing the change in the subject.
  • Observer can be added/removed at any time irrespective of type of the subject.
  • This pattern is also allow loose coupling between subject and observers.
blog comments powered by Disqus