The observer pattern has ben categorized as a behavioral software design pattern. In Observer Pattern there is a subject and it will maintain a list of observers as dependents.
The object which is being watched is called the subject. The objects which are watching the state changes are called observers.The relationship between subject and observers is one to many. In other words, a subject can have many number of observers. Whenever the subject (the state of the subject) is changed, the list of related dependents will be notified.
Real world use-cases for Implementing Observer Pattern
If you start to think for real world situations where we can implement the observer pattern, you will be ended up with many number of (even uncountable) use cases. Here i am going to point two sample scenarios for giving you some understanding of the use of observer pattern.
- Online Store : Customer is interested in buying a product (lets say wrist watch) online and found that the product is out of stock. In this case, the customer (observer) can subscribe for the product (Subject) for getting the notification when the stock is available. The product (subject) will maintain a list of customers (observers) to be notified when the product is available.
- Flight Schedule : Passengers may be interested of getting the information about the changes of the flight schedules. In such case, the passengers (observers) can subscribe for a flight schedule (subject) and they will receive the update if the schedule is changed.
Implementation with Java
The sample implementation of Observer pattern can be shown as follows. please see the below sample classes.
Subject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Subject { | |
private String status; | |
private List<Observer> observers = new ArrayList<Observer>(); | |
public String getStatus() { | |
return status; | |
} | |
public void setStatus(String status) { | |
System.out.println("changing the status to [" + status + "] "); | |
this.status = status; | |
this.notifyObservers(); | |
} | |
public void subscribe(Observer observer) { | |
observers.add(observer); | |
} | |
public void unsubscribe(Observer observer) { | |
observers.remove(observer); | |
} | |
private void notifyObservers() { | |
System.out.println("notifying observers"); | |
observers.stream().forEach((observer) -> { | |
observer.receiveUpdate(this); | |
}); | |
} | |
} |
ObserverA.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ObserverA implements Observer { | |
@Override | |
public void receiveUpdate(Subject subject) | |
{ | |
System.out.println("update received by [" + this.getClass().getSimpleName() + "]"); | |
} | |
} |
The implementation of ObserverB and ObserverC are same as above classes. Please refer the source code for more details.
MainApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@SpringBootApplication | |
public class MainApplication implements CommandLineRunner { | |
public static void main(String[] args) { | |
SpringApplication.run(MainApplication.class, args); | |
} | |
@Override | |
public void run(String… strings) throws Exception | |
{ | |
System.out.println("==== started the MainApplication"); | |
Subject subject = new Subject(); | |
//Subscribing ObserverA | |
ObserverA observerA = new ObserverA(); | |
subject.subscribe(observerA); | |
//Subscribing ObserverB | |
ObserverB observerB = new ObserverB(); | |
subject.subscribe(observerB); | |
//ObserverC remain as unsubscribed | |
subject.setStatus("Started"); | |
System.out.println("\n"); | |
subject.setStatus("In-Progress"); | |
System.out.println("\n"); | |
subject.setStatus("Completed"); | |
System.out.println("==== completed the MainApplication"); | |
} | |
} |
You can notice that ObserverA and ObserverB has been subscribed for the Subject. The ObserverC has not subscribed for any subject and it remains as unsubscribed. The status of the subject has been changed three times. Therefore theoretically. each observers should get notified whenever the state of the object is changed and here it should be three times.
Lets run the application and see the output.
Source Code and How to Run
The full source code of the implementation of the observer pattern can be found at GitHub. Click here to download.
The implementation has been made as a Spring Boot CLI (command line) project. Therefore the project can be build and run with following command.
mvn spring-boot:run
After running the above program, you will get the following output.
Here you can see that ObserverC does not get the notification because, it is not subscribed for the Subject.
Coupling Observer with Subject (Is it required or not ?)
In some of the implementation for the Observer Pattern available in the Internet, you might have seen that the Observers are tightly coupled with Subject. This happens when the Observer keeps a reference to the Subject (Observer maintain a member variable that refer to the Subject). This introduces and additional and unnecessary coupling between Subject and Observers. Those implementations are poor implementations of the Observer Pattern.
The Subject maintains a list of Observers who are interested about the subject. Therefore Subject can notifies the observers about the state changes when they happen. There is no valid point of maintaining a reference from observer to Subject as there is no communication happens from Observer to Subject.
If the Observer wants to know about the Subject, then it can be received as a parameter of the method which is used/invoked by the Subject to notify the observers about the state changes.
In a proper software design , the coupling should be low and cohesion should be high.
Observer Pattern with SOLID Design Principles
Observer Pattern follows the “Open Closed Principle” of the SOLID Design Principles. Open closed principle states that “the class should be opened for extension and closed for modification“. This means that the it should be able to extend the class without changing the source code of the class. Therefore, It should be possible to add Observers for the Subject without changing the source code of the Subject class.
Are Observer Pattern and Publisher-Subscriber Pattern are same?
The majority of the developers are having a misunderstanding that Observer Pattern and Publisher-Subscriber Pattern are same. No! They are NOT. The reason behind this misunderstanding is that they thinks that Subject as Publishers and Observers as Subscribers. Therefore they thinks that publisher-subscriber pattern and observer pattern are same. Publisher-Subscriber pattern is a kind of variation of the Observer Pattern.
Click here if you want to look at the Publisher-Subscriber Pattern
The differences between Publisher-Subscriber and Observer pattern can be shown in the following diagram.
Lets summarize the differences between Publisher-Subscriber pattern and Observer pattern as follows.
- In the Observer pattern, Subject maintains a list of Observers and therefore Subjects aware of how to notify observers when there is a state change occurs. Whereas, in Publisher/Subscriber, publishers and subscribers don’t need to know each other. They simply communicate with the help of middle layer message broker (or message queue).
- In Publisher/Subscriber pattern, components are completely decoupled with compared to Observer pattern (In Observer pattern, Subject and Observers are loosely coupled).
- Observer pattern is mostly implemented in a synchronous way, i.e. the Subject calls the appropriate method of all its observers when some event occurs. The Publisher/Subscriber pattern is mostly implemented in an asynchronous way (using message queue).
- Observer pattern need to be implemented in a single application address space. It will be implemented within the single application. On the other hand, Publisher/Subscriber pattern is more of a cross application pattern. Publisher and Subscriber may resides in two different applications. each of them will communicate over message broker or message queue.
Despite of the differences between these patterns, some might say that Publisher-Subscriber pattern is a variation of Observer pattern because of the conceptual similarity between them.
References:-
https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c