Observer Pattern

This lesson discusses the observer pattern in detail using a coding example.

What is the observer pattern? #

The observer pattern is a major behavioral design pattern. It allows objects (observers) that have subscribed to an event to wait for input and react to it when notified; meaning, they don’t have to continuously keep on checking whether the input has been provided or not. The main subject maintains a list of all the observers, and whenever the event occurs, it notifies the observers so they can update their states accordingly.

Let’s look at a real-life example that we can map to this pattern. Consider a website that posts interesting articles. Every day you visit the site to check for new articles and if there is none you revisit after some time/days. What if you get a subscription to the website instead? Once you have the subscription, you’ll get notified every time a new article is posted. So now, instead of checking the site every few hours, you just wait for the notification for the new article.

Example #

Let’s look at a coding example to understand the implementation of the observer pattern.

Press + to interact
class Subject{
constructor(){
this.observerList = []
this.newArticlePosted = false
this.articleName = null
}
subscribe(observer){
this.observerList.push(observer)
}
unsubscribe(observer){
this.observerList = this.observerList.filter(obs => obs !== observer)
}
notify(){
if(this.newArticlePosted){
this.observerList.forEach(subscriber => subscriber.update())
}
else{
return
}
}
getUpdate(){
return this.articleName
}
postNewArticle(articleName){
this.articleName = articleName
this.newArticlePosted = true
this.notify()
}
}
class Observer{
constructor(){
this.subject = new Subject()
}
update(){
if(subject.getUpdate() == null){
console.log("No new article")
}else{
console.log(`The new article ${subject.getUpdate()} is posted`)
}
}
setSubject(subject){
this.subject = subject
}
}
var subject = new Subject()
var observer = new Observer()
observer.setSubject(subject)
subject.subscribe(observer)
observer.update()
subject.postNewArticle("Dark matter")

Explanation

In this example, we have the Subject class that stores the list of all observers and notifies them if a new article gets posted on the website.

class Subject{
    constructor(){
        this.observerList = []
        this.newArticlePosted = false
        this.articleName = null
    }   
   //code..
}

The constructor initializes the list observerList that stores all the observers. It has two other properties: newArticlePosted (boolean variable to check whether a new article has been posted or not) and articleName (the name of the article).

It also defines the subscribe and unsubscribe functions to register or remove an observer from the subscription.

subscribe(observer){
   this.observerList.push(observer)
}
  
unsubscribe(observer){
     this.observerList = this.observerList.filter(obs => obs !== observer)
}

It also has the getUpdate function that returns the name of the new article posted.

getUpdate(){
        return this.articleName
}

How is the new article posted? Using the postNewArticle function.

postNewArticle(articleName){
    this.articleName = articleName
    this.newArticlePosted = true
    this.notify()
}

When a new article is posted, its name is set, the variable newArticlePosted is set to true, and the observer is notified about it by invoking the notify function.

notify(){
   if(this.newArticlePosted){        
     this.observerList.forEach(subscriber => subscriber.update())
   }
   else{
      return null
   }
}

The notify function checks if a new article is posted; if so, it sends the update to each subscriber in the list; else, it returns.

The Observer class is defined as follows:

class Observer{
    constructor(){
        this.subject = new Subject()
    }
    //codee..
   setSubject(subject){
     this.subject = subject
   }
}

The constructor initiates an instance of Subject and sets it using setSubject. The funtion accepts a Subject instance and sets it as the subject for the observer.

The Observer also has the update function.

    update(){
        if(subject.getUpdate() == null){
            console.log("No new article")
        }else{
            console.log(`The new article ${subject.getUpdate()} is posted`)
        }
    }

This function is invoked by the Subject to notify the observer about the new article getting posted. Hence, it checks for an update; if a new article is found, it displays the notification for it else it returns No new article.

When to use the observer pattern?

The observer pattern can be used:

  • To improve code management by breaking down large applications into a system of loosely coupled objects.

  • To provide greater flexibility by enabling a dynamic relationship between observers and subscribers, otherwise, not possible due to tight coupling.

  • To improve communication between different parts of the application.

  • To create a one-to-many dependency between objects that are loosely coupled.


Now that you know what the observer pattern is, it’s time to implement it!