Whenever we write code, we always try to make sure it is readable and extensible. However, as time passes and multiple people contribute to the same codebase, it can gradually become messy. This usually happens because everyone has their own way of writing logic and structuring classes and objects.
This is where design patterns come into the picture. During the design phase of a project, we should think about which design patterns are appropriate and how our objects will be created, structured, and expected to behave in the future.
Considering design patterns gives the team a solid structure or blueprint to follow. When everyone follows the same pattern, collaboration becomes smoother, and team members can contribute simultaneously without making the codebase inconsistent or difficult to maintain.
Today i want to talk about Observer Design Pattern also called as pub sub design pattern. I personally find it very interesting to see how we can make sure data is been broadcasted to multiple required classes without violating the SOLID principle.
There are two parties involves in this design is called Obervable and the other is called observer.
Observable is the one where the actual data is being present which is being observed by multiple observers. The relationship between observable and observer is 1:N.
Here is representation of the pattern:
Composition over Inheritance
Its good and safe to work with Interfaces.
Observable
The Observable interface provides extensibility by defining a contract for subjects that can be observed. Any new concrete class can implement this interface without affecting existing observers. This allows us to introduce new observable entities — such as a PriceChangeObservable for dresses — while reusing the same observer mechanism. The system remains flexible and follows the Open/Closed Principle.
Observer
In the Observer pattern, we can dynamically add or remove any number of observers at runtime.
The observable maintains a list of observers and notifies them whenever its state changes.
This design promotes loose coupling between the subject and observers, making the system flexible, extensible, and easy to maintain.
Class WeatherStation implements IObservable {
private int temperature;
private List<IObserver> observers;
public WeatherStation(){
this.observers = new ArrayList<>();
}
@Override
public void add(IObserver observer) {
observers.add(observer);
}
@Override
public void remove(IObserver observer){
observers.remove(observer);
}
public void setTemperature(int temperature){
this.temperature = temperature;
for(IObserver observer: observers){
observer.update();
}
}
public int getTemperature(){
return this.temperature;
}
}
class PhoneDisplay implements IObserver {
private WeatherStation station;
public PhoneDisplay(WeatherStation station){
this.station = station;
}
@Override
public void update(){
int updatedTemperature = this.station.getTemperature();
System.out.println("The Updated temperature is:: " + updatedTemperature);
}
}
class Main {
public static void main(String[] args){
IObservable weatherStation = new WeatherStation();
IObserver phoneDisplay = new PhoneDisplay(weatherStation);
weatherStation.add(phoneDisplay);
weatherStation.setTemperature(5);
weatherStation.remove(phoneDisplay);
}
}
There are two ways where observer design pattern can be implemented. PUSH and PULL model.
The above code reference is PULL model.
PUSH Model:
- whenever there is a change in data it will be notified to the list of observers by passing the data like this
for(IObserver observer: observers){ observer.update(this.temperature); }
PULL Model:
- Whenever there is a data change the observer can itself has a instance of the concrete implementation of observable interface and make use of that as per required.

Top comments (0)