Introduction
The observer design pattern states that, objects of interest should be able to update the state change to the interested clients. Where in objects of interest and interested clients are called Publishers and Subscribers respectively.
Why is this pattern needed?
Lets say there are two types of magazine readers paperback and digital. Each of these readers rushes to the shop when any new volume of their beloved magazine about to release.
In the above scenario, do you see the problem? For the readers it is a waste of time to travel to the store in case the magazine has not arrived yet. Wouldn’t it be better if the reader gets notified when the mazgine actually arrives.
The above is an exact problem that the observer design pattern tries to solve. Now let’s dive in details of the same.
Observer pattern Internals
This pattern needs three main components as listed below.
- Publisher objects which should support API’s to allow subscribe or unsubscribing to certain events.
- Subscriber Interface should contain bare minimum API notify(…). Which will gets called when change happens.
- Subscriber objects should implement a common subscriber interface and respective business logic.
Observer pattern with example
Let’s implement the mobile automatic brightness adjustment feature.
Feature requirement of mobile automatic brightness adjustment
- Publisher object should report different levels of light brightness from the ambient light sensor.
- Subscriber object should set the respective mobile brightness based on the level received from publisher.
- Different levels of surrounding light should be categorized as low, medium and high (This can be further fine grained, for simplicity keeping it coarse)
- Different levels of mobile screen brightness should be categorized as low, medium and high.
Automatic brightness feature Implement in java
AmbientSensorPublisher.java
package working.example.tech.DesignPattern.Bhavioural.ObserverPattern;
import working.example.tech.interfaces.TestCaseRunner;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class AmbientSensorPublisher implements TestCaseRunner {
private Set<ObserverInterface> observers;
public AmbientSensorPublisher() {
observers = new HashSet<>();
}
public void subscribe(ObserverInterface iFace) {
observers.add(iFace);
}
public void unsubscribe(ObserverInterface iFace) {
observers.remove(iFace);
}
public void updateObservers(LightSensitivity level) {
for (ObserverInterface iFace : observers) {
iFace.notifyState(level);
}
}
@Override
public void RunTest() {
// TODO Auto-generated method stub
AutoBrightnessAdjustment auto = new AutoBrightnessAdjustment();
this.subscribe(auto);
this.updateObservers(LightSensitivity.LOW);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.updateObservers(LightSensitivity.MEDIUM);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.updateObservers(LightSensitivity.HIGH);
}
@Override
public void showOut() {
// TODO Auto-generated method stub
}
}
LightSensitivity.java
package working.example.tech.DesignPattern.Bhavioural.ObserverPattern;
public enum LightSensitivity {
LOW,
MEDIUM,
HIGH
}
AutoBrightnessAdjustment.java
package working.example.tech.DesignPattern.Bhavioural.ObserverPattern;
public class AutoBrightnessAdjustment implements ObserverInterface {
@Override
public void notifyState(LightSensitivity level) {
// TODO Auto-generated method stub
System.out.println("Current light sensitivity is " + level +
" Setting the Mobile Brightness to :" + level);
}
}
ObserverInterface.java
package working.example.tech.DesignPattern.Bhavioural.ObserverPattern;
import working.example.tech.DesignPattern.Bhavioural.ObserverPattern.LightSensitivity;
public interface ObserverInterface {
void notifyState(LightSensitivity level);
}
Main.java
working.example.tech.DesignPattern.Bhavioural.ObserverPattern.AmbientSensorPublisher;
import working.example.tech.interfaces.TestCaseRunner;
public class Main {
public static void main(String[] args) {
AmbientSensorPublisher sensor = new AmbientSensorPublisher();
sensor.RunTest();
}
}
Conclusion
In this blog we discussed a widely used observer design pattern with easy to understand example. Hope this helps, stay tuned for more blogs on design patterns!