Observer Design Pattern

The goal is to ensure that when one object changes state, all its dependents are automatically notified and updated.

The Observer Design Pattern is frequently used in situations where there is an entity whose state can change due to different conditions, and there is a need for observers to keep track of these state changes and receive notifications when they occur. This pattern can involve multiple observables and observers, where a single observable may have multiple observers in a straightforward scenario.

If we can successfully define an observable interface, we've essentially accomplished the majority of the design. The first three functionalities are of utmost importance for designating an object as observable:

  1. Add: This allows the inclusion of an observer into the list of observers.

  2. Remove: It enables the removal of an observer from the list.

  3. Notify: The notification mechanism is essential to inform all observers whenever there is a change in the object's state.

  4. State (set & get) - The central aspect of observation revolves around detecting changes, and the notifySubscriber method should be invoked whenever alterations occur. It is advisable to include both a setter and a getter inside the interface.

It is not necessary to have the state in the interface but it is a good practice to wrap it in the interface.

Example:

In this scenario, we are monitoring the availability of a product in an online store. Whenever a new stock is added, we notify all users who have subscribed to receive notifications about this specific product.

  1. Observable (Heart of the pattern)
package Observable;

import Observer.NotificationAlertObserver;

public interface StockObservable {

    public void add(NotificationAlertObserver observer);

    public void remove(NotificationAlertObserver observer);

    public void notifySubscriber();

    public void setStockCount(int newStockAdded);

    public int getStockCount();
}

A concrete class example of Observable

package Observable;

import Observer.NotificationAlertObserver;

import java.util.ArrayList;
import java.util.List;

public class IphoneObservableImpl implements StockObservable{

    private int stockCount;

    private List<NotificationAlertObserver> observerList = new ArrayList<>();

    @Override
    public void add(NotificationAlertObserver observer) {
        observerList.add(observer);
    }

    @Override
    public void remove(NotificationAlertObserver observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifySubscriber() {
        for (NotificationAlertObserver observer: observerList){
            observer.update();
        }
    }

    @Override
    public void setStockCount(int newStockAdded) {
        if (stockCount==0){
            notifySubscriber();
        }
        stockCount+=newStockAdded;
    }

    @Override
    public int getStockCount() {
        return stockCount;
    }
}
  1. Observer Interface
package Observer;

public interface NotificationAlertObserver {
    public void update();
}

Email observer Implementation

package Observer;

import Observable.StockObservable;

public class EmailAlertObserver implements NotificationAlertObserver{

    String emailId;

    StockObservable observable;

    public EmailAlertObserver(String emailId, StockObservable observable){
        this.emailId = emailId;
        this.observable = observable;
    }

    @Override
    public void update() {
        sendEmail(emailId,"Product is in Stock hurry up");
    }

    private void sendEmail(String email, String message) {
        System.out.println("mail sent to - "+ email);
    }
}

Mobile observer Implementation

package Observer;

import Observable.StockObservable;

public class MobileAlertObserver implements NotificationAlertObserver{

    String mobileNumber;

    StockObservable observable;

    public MobileAlertObserver(String mobileNumber, StockObservable observable) {
        this.mobileNumber = mobileNumber;
        this.observable = observable;
    }

    @Override
    public void update() {
        sendSms(mobileNumber,"Product is in Stock");
    }

    private void sendSms(String mobileNumber, String message) {
        System.out.println("Message sent to this "+ mobileNumber);
    }
}

Usage

import Observable.IphoneObservableImpl;
import Observable.StockObservable;
import Observer.EmailAlertObserver;
import Observer.MobileAlertObserver;
import Observer.NotificationAlertObserver;

public class Store {

    public static void main(String args[]){
        StockObservable iphoneStockObservable = new IphoneObservableImpl();

        NotificationAlertObserver observer1 = new EmailAlertObserver("xyz@gmail.com", iphoneStockObservable);
        NotificationAlertObserver observer2 = new EmailAlertObserver("xy1@gmail.com", iphoneStockObservable);
        NotificationAlertObserver observer3 = new MobileAlertObserver("3749273", iphoneStockObservable);

        iphoneStockObservable.add(observer1);
        iphoneStockObservable.add(observer2);
        iphoneStockObservable.add(observer3);


        iphoneStockObservable.setStockCount(10);
    }
}

Conclusion: Observer design pattern is a methodology employed when there is a need for monitoring a particular object or situation.