Close
Observer Design Pattern deception via a binnacle.

Observer Design Pattern

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.
Observer design pattern illustration via naive implementation class diagram of auto brightness feature.

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!

More blogs