What is the Observer Design Pattern? Why and When Should We Use This Pattern? We’ll discuss these questions in this article.
Observer Design pattern belongs to Behavioral patterns, but what is this Behavioral pattern?
Behavioral patterns focus on how objects interact with each other, rather than creation of object, as seen creational pattern. It helps in distribute the responsibilities within a program and describe how objects communicate with one another. These patterns deals with complex control flow that can be hard to understand during execution. Instead of worrying about the flow of control, behavioral patterns helps you to focus on how objects are connected and work together.
Don’t worry if you don’t understand the definition of Behavioral pattern. Later section of this blog, You'll understand it more clearly.
Observer design pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. See here the behavior of the observer changes on the state change.
When to use this pattern?
The Observer Pattern is useful when you want one object to notify many other objects about changes, but without tightly connecting them. The notifying object, which we call subject here, doesn’t need to know about the details of the objects it is notifying(Observers).
Before moving forward, lets see some real life scenarios:
News and Subscribers: when new channel/app publish an news update. The subscribers who are observers, get notified when there is a update.
Weather report: when there is change in temperature or other parameters. It should be notified to all the devices which are displaying these weather reports.
Cricket updates: When there is a change in score. The change should notified to all the components because there will corresponding changes in average, runs to win, and the score should be added against the player, etc.
E-Commerce Notifications: You want to know when a sold-out product is back in stock. When the product is restocked the e-commerce platform should notify all interested customers (observers) by sending an email or app notification.
Email or SMS Alerts: Banks send notifications when a transaction happens in your account. The banking system (subject) tracks your account for any changes. Observers like email or SMS services get notified to send alerts to you.
Structure/UML diagram
In the UML diagram, there are two interfaces:
One for the subject and other for the observer. The observer has one abstract method notify(). This method will be implemented by the corresponding concrete class.
The Subject interface has three abstract methods: addObservers(), removeObservers(), and notify(). To keep track of all the subscribed observers, we need a collection of observers in the Subject class. This is why the addObservers() and removeObservers() methods are necessary.
Now lets see the code:
public interface Observer {
void update(Long score);
}
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public class CricketMatch implements Subject{
private List<Observer> observers; //this can be any type of collection like set, map. choose based on the use case .
private Long score; //
public CricketMatch(){
observers = new ArrayList<Observer>();
score = 0L;
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for(Observer observer : observers){
observer.update(score);
}
}
public void setScore(Long score) {
this.score = score;
notifyObservers();
}
}
public class AverageScoreObserver implements Observer{
@Override
public void update(Long score) {
System.out.println("average score: " + score);
}
}
public class RunsAganistPlayer implements Observer{
@Override
public void update(Long score) {
System.out.println("runs by player one: " + score);
}
}
public class RunsToWin implements Observer {
@Override
public void update(Long score) {
System.out.println("Runs to win: " + score);
}
}
public class Main {
public static void main(String[] args) {
CricketMatch match = new CricketMatch();
Observer runsToWinObserver = new RunsToWin();
Observer runsAganistPlayerObserver = new RunsAganistPlayer();
Observer avgScoreObserver = new AverageScoreObserver();
match.registerObserver(runsToWinObserver);
match.registerObserver(runsAganistPlayerObserver);
match.registerObserver(avgScoreObserver);
match.setScore(100L);
}
}
In conclusion, the Observer Design Pattern promotes loose coupling by allowing objects to notify multiple dependents of changes without direct communication. It is especially useful in event-driven systems and real-time applications. Understanding its implementation can greatly enhance flexibility and scalability in your software design.
Stay tuned for more on design patterns in my next blogs. 😊