Suppose there are a set of objects of one type watching an object of another type such that whenever there is change in the watched object, all the watching objects are informed or notified of this change.
The design pattern which should be implemented in this case is Observer design pattern.
The object which is being watched and which sends notification is called Subject.
The objects which are waiting for any update in Subject are called Observers.
Thus, Observer is a design pattern in which an object(called Subject) maintains a list of other objects(called Observers) which are watching the subject. The Subject notifies them for any changes in it usually by calling one of the methods of Observer object.
Observer Pattern : Practical Scenarios
Following real life scenarios will clarify the understanding of this pattern and let you identify the use case where this pattern should be applied during application development.
Scenario 1
When shopping on an e-commerce applications, the product you want to purchase is out of stock and you ask to be informed when the product becomes available again.
Now imagine there are 10 customers interested in the same product(which is not in stock currently) and all choose to be informed of its availability. Here, the product is the Subject and the customers waiting are Observers.
As soon as the product is available(state change), all customers are informed.
Scenario 2
A reader visits a website such as codippa.com. He reads an article and likes it.
Now he wants to be informed whenever a new article is posted on the website. The reader provides his email and subscribes to the reader list.
Here the website is the Subject and the readers are Observers. As soon as there is a new article posted on the website(state change), all the readers are notified.
Design
This section will show you how to implement Observer pattern in Scenario 2 discussed above where readers register to be notified whenever a new article is posted on a website.
In this scenario, the website will be the Subject and the readers will be the Observer.
In Observer pattern, generally there is an interface Subject which contains methods to add, remove and notify observers.
This interface is implemented by a class representing an actual subject. Thus in this example, website will be the actual subject.
There is an interface Observer which contains at least a method which is called by the Subject. This interface is implemented by a class representing an actual observer.
Thus in this example, visitors will be the actual observers
The class diagram for this implementation should be as below
Note that Subject interface has methods to add, remove and notify observers.Website
, which is the actual subject has a list of observers and implements the methods which add and remove observer objects from this list.
This class has fields which represent the name of the new post and a boolean
which signifies a new post availability.
Observer interface has a single method which is called by the subject in order to notify observer.Visitor
is the actual observer and has a single field representing the name of the visitor.
Implementation Example
Java code based on the above class diagram is given below.
public interface Subject { /** * Adds an observer to the list of observers * @param observer */ void registerObserver(Observer observer); /** * Remove an observer from the list of observers * @param observer */ public void unregisterObserver(Observer observer); /** * Notify all observers */ public void notifyObservers(); }
Subject
is an interface which has method declarations to register, unregister and notify observers. Any actual subject which implements this interface should define these three methods.
Let’s define an actual subject, which, in our case will be a website.
import java.util.ArrayList; import java.util.List; public class Website implements Subject { /** * List of observers */ private List observers = new ArrayList(); /** * Signifies whether a new post is available */ private boolean isNewPost; /** * Name of the post. This will be notified to the observers */ private String postName; @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void unregisterObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers() { //check if there is a new post available if (isNewPost()) { //iterate over all registered observers for (Observer observer : observers) { //call observer's method to notify observer.update(postName); } } } public boolean isNewPost() { return isNewPost; } public void setNewPost(boolean isNewPost) { this.isNewPost = isNewPost; } public void setPostName(String postName) { this.postName = postName; } }
Actual subject has a list of observers which need to be notified for new article submissions.
Method notifyObservers()
iterates over all registered observers using enhanced for loop and notifies them if a new article is posted on the website.
Let’s see how an observer will look like.
public interface Observer { /** * Method of an observer which will be called by the subject for * notification * * @param postName */ public void update(String postName); }
Observer has only one method which is called by the subject when it wants to notify the observer. Actual observer will implement this interface and provide an implementation of this method.
public class Visitor implements Observer { /** * Name of visitor */ String visitorName; @Override public void update(String postName) { // print message System.out.println("Hello " + visitorName + "," + " New post \"" + postName + "\"" + " is available on codippa.com"); } public void setVisitorName(String visitorName) { this.visitorName = visitorName; } }
Visitor
is an implementation of Observer
interface.
It has a field which represents the name of visitor and implementation of interface method. This method prints a message that a new post is available on the website.
Now let’s test our observer pattern implementation.
public class ObserverDriver { public static void main(String[] args) { // create observer object Visitor visitorOne = new Visitor(); // set name visitorOne.setVisitorName("Visitor One"); // create another observer object Visitor visitorTwo = new Visitor(); // set name visitorTwo.setVisitorName("Visitor Two"); // create an object of the subject Website codippa = new Website(); // set the name of new post codippa.setPostName("Design Patterns in java"); // set new post flag to false codippa.setNewPost(false); // register observers codippa.registerObserver(visitorOne); codippa.registerObserver(visitorTwo); // set new post flag to true codippa.setNewPost(true); // notify observers codippa.notifyObservers(); System.out.println("Unregistering Visitor One"); // unregister first observer codippa.unregisterObserver(visitorOne); // again notify observers codippa.notifyObservers(); } }
The above class creates two Visitor
objects which will be the actual observers and a Website
object which is the actual subject on which the observers are watching.Website
registers the visitors and notifies them when any new post is available on the website.
From the output you can see that both the visitors are notified. Then, one visitor is unregistered and again the visitors are notified.
This time only one visitor is notified and not the one who was unregistered.
Output
Hello Visitor One, New post “Design Patterns in java” is available on codippa.com
Hello Visitor Two, New post “Design Patterns in java” is available on codippa.com
Unregistering Visitor One
Hello Visitor Two, New post “Design Patterns in java” is available on codippa.com
Benefits of Observer Pattern
From the discussion on Observer design pattern, following characteristics of this pattern are clearly visible.
- There is loose coupling or very less dependency among Subject and Observer objects.
The subject does not need to know anything about observers.
Further, sinceObserver
is an interface, we can easily change the implementations in the actual observers.Subject
would be least concerned about it. - A subject can register any number of observers. If a new observer wants to register with the subject, no code change is required.
Also, if a new observer class will be created, it will simply implementObserver
interface and there will be no change in existing code