Observer Design Pattern in Java

Let’s understand first what is Observer Design pattern and where we can use it.

Observer Design Pattern

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

The concept of observer design pattern is very simple, all it promises us that whenever root object on which other objects are dependent updates its state, it will notify all of its dependent objects.

You can consider an example of Newspaper subscription to understand this better. We all know, whenever Newspaper company issues a new copy of a paper, all the interested parties who have an active subscription ( dependent objects ) receives that copy. Observer pattern is based on the same concept, except in its terminology Newspaper company is knows as “Subject” and members of newspaper subscription are known as “Observers”.

Below is the perfect example of Observer Design pattern, followed by real world example.

import java.util.LinkedList;
import java.util.List;
public class ObserverDemo {
    public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
concreteSubject.attachObserver(new ConcreteObserveOne(concreteSubject));
concreteSubject.attachObserver(new ConcreteObserveTwo(concreteSubject));
concreteSubject.attachObserver(new ConcreteObserveThree(concreteSubject));
        concreteSubject.setSubjectState("ABC");
concreteSubject.setSubjectState("XYZ");
}
}
interface Observer {
void onUpdate();
}
interface Subject {
void attachObserver(Observer observer);
    void deattachObserver(Observer observer);
    void notifyObservers();
}
class ConcreteSubject implements Subject {
    private String subjectState = "Test";
private List observerLinkedList;
    public ConcreteSubject() {
this.observerLinkedList = new LinkedList<>();
}
    public String getSubjectState() {
return subjectState;
}
    public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
this.notifyObservers();
}
    public List getObserverLinkedList() {
return observerLinkedList;
}
    public void setObserverLinkedList(List observerLinkedList) {
this.observerLinkedList = observerLinkedList;
}
    @Override
public void attachObserver(Observer observer) {
if (observerLinkedList.contains(observer)) return;
this.observerLinkedList.add(observer);
}
    @Override
public void deattachObserver(Observer observer) {
if (!observerLinkedList.contains(observer)) return;
this.observerLinkedList.remove(observer);
}
    @Override
public void notifyObservers() {
this.observerLinkedList.forEach(ob -> ob.onUpdate() );
}
}
class ConcreteObserveOne implements Observer {
    private ConcreteSubject subject;
    public ConcreteObserveOne(ConcreteSubject subject) {
this.subject = subject;
}
    @Override
public void onUpdate() {
System.out.println(this.getClass().getSimpleName() + " RECEIVED NEW STATE--> " + subject.getSubjectState());
}
}

class ConcreteObserveTwo implements Observer {
    private ConcreteSubject subject;
    public ConcreteObserveTwo(ConcreteSubject subject) {
this.subject = subject;
}
    @Override
public void onUpdate() {
System.out.println(this.getClass().getSimpleName() + " RECEIVED NEW STATE--> " + subject.getSubjectState());
}
}

class ConcreteObserveThree implements Observer {
    private ConcreteSubject subject;
    public ConcreteObserveThree(ConcreteSubject subject) {
this.subject = subject;
}
    @Override
public void onUpdate() {
System.out.println(this.getClass().getSimpleName() + " RECEIVED NEW STATE--> " + subject.getSubjectState());
}
}

One key point we should keep in mind while implementing Observer that, we should always try for loose coupling between subject and observers, because if these two are very tightly coupled then we are inviting future scalability issues.

For those who want to see this design pattern with real world example, I have coded below example in the context of HR and its Employee’s vital notice exchange. This is not a perfect example of live notice exchange system but would be sufficient to understand observer design pattern well.

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class RealWordObserverDemo{
public static void main(String[] args) {
Notice notice = new Notice();
notice.setTitle("Welcome to the Company");
notice.setDescription("We are delight to have you on our boat.");
notice.setIssuedOn(new Date(System.currentTimeMillis()));
DejavuHRDepartment dejavuHRDepartment = new DejavuHRDepartment(notice);
        dejavuHRDepartment.attachEmployeeToNotificationList(
new EmployeeImpl(dejavuHRDepartment, "John")
);
dejavuHRDepartment.attachEmployeeToNotificationList(
new EmployeeImpl(dejavuHRDepartment, "Silva")
);
dejavuHRDepartment.attachEmployeeToNotificationList(
new EmployeeImpl(dejavuHRDepartment, "Milky")
);
dejavuHRDepartment.attachEmployeeToNotificationList(
new EmployeeImpl(dejavuHRDepartment, "Ria")
);
        notice = new Notice();
notice.setTitle("Tomorrow is Holiday");
notice.setDescription("Company has declared tomorrow as holiday, Enjoy.");
dejavuHRDepartment.setCurrentNotice(notice);
}
}
//Subject
interface HRDepartment {
void attachEmployeeToNotificationList(Employee employee);
void detachEmployeeFromNotificationList(Employee employee);
void notifyEmployeesForNewNotice();
}
//Observer
interface Employee {
void onNewNotice(Notice notice);
}

//Notice
class Notice {
private String title;
private String description;
private Date issuedOn;
    public String getTitle() {
return title;
}
    public void setTitle(String title) {
this.title = title;
}
    public String getDescription() {
return description;
}
    public void setDescription(String description) {
this.description = description;
}
    public Date getIssuedOn() {
return issuedOn;
}
    public void setIssuedOn(Date issuedOn) {
this.issuedOn = issuedOn;
}
}

class DejavuHRDepartment implements HRDepartment{
    private List employeeLinkedList;
private Notice currentNotice;
    public DejavuHRDepartment(Notice currentNotice) {
employeeLinkedList = new LinkedList<>();
this.currentNotice = currentNotice;
}
    @Override
public void attachEmployeeToNotificationList(Employee employee) {
if( employeeLinkedList.contains(employee) ) return;
employeeLinkedList.add(employee);
employee.onNewNotice(this.currentNotice);
}
    @Override
public void detachEmployeeFromNotificationList(Employee employee) {
if( !employeeLinkedList.contains(employee) ) return;
employeeLinkedList.remove(employee);
}
    @Override
public void notifyEmployeesForNewNotice() {
employeeLinkedList.forEach(emp -> emp.onNewNotice(this.currentNotice));
}
    public Notice getCurrentNotice() {
return currentNotice;
}
    public void setCurrentNotice(Notice currentNotice) {
this.currentNotice = currentNotice;
this.notifyEmployeesForNewNotice();
}
}
class EmployeeImpl implements Employee{
    private DejavuHRDepartment dejavuHRDepartment;
private String name;
    EmployeeImpl(DejavuHRDepartment dejavuHRDepartment, String name){
this.dejavuHRDepartment = dejavuHRDepartment;
this.name = name;
}
    @Override
public void onNewNotice(Notice notice) {
StringBuilder message = new StringBuilder();
message.append("My Name is ").append(this.name);
message.append("\n and I've just got to know that HR department has updated Notice. ");
message.append("\n and the title of new Notice is " + notice.getTitle() + "\n\n");
System.out.println(message);
}
}

Let me know guys if you have anything in mind to discuss regarding this. :) And here is the download link of source code zip.

Download Source code

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.