Observer design pattern

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

It is mainly used to implement distributed event handling systems, in "event driven" software. Most modern languages such as C# have built in "event" constructs which implement the observer pattern components, for easy programming and short code.

[Wikipedia]

Intro

Let's say that we have a few supermarkets that wishes to know some of their competitors prices, and match their prices according to the newest supermarket that has joined the app. At this project, we wil represent them as Clients of our app. They will be able to add client to our app,remove client and notify other companies about their prices. After they will register, and change the prices, they will use the update method of the ObserverPack.Observer interface, this method will update the values and print them to all the registered clients.

Observer


// The Observers update method is called when the store changes prices.
public interface Observer {
    public void update(double breadPrice, double milkPrice, double meatPrice);
    }

StoreObserver


    // Represents each Observer that is updating prices as a Client
public class StoreObserver implements Observer {
    private double milkPrice;
    private double breadPrice;
    private double meatPrice;
    private static int numOfClients = 0;  //Static variable to count all the clients.
    private int clientObserverId;
    private Client client;

    public StoreObserver(Client newClient){
        this.client = newClient;
        this.clientObserverId = numOfClients;
        numOfClients++;
        System.out.println("New Client Observer " + this.clientObserverId);
        client.addClient(this); //Add the client to the array list of the price followers.
    }

    public void update(double milkPrice, double breadPrice, double meatPrice) {
        this.milkPrice = milkPrice;
        this.breadPrice = breadPrice;
        this.meatPrice = meatPrice;
        printThePrices();
    }

    public void printThePrices(){
        System.out.println("Client number "+ clientObserverId + "\n Milk: " + milkPrice + "\n Bread: " +
                breadPrice + "\n Meat: " + meatPrice + "\n");
    }
}

Client


   // This interface handles adding and deleting stores that wish to get updates about prices.
public interface Client {
    public void addClient(Observer o);
    public void removeClient(Observer o);
    public void notifyTheClients();
}

HandleStores


import java.util.ArrayList;
// Uses the Client interface to update all Observers.
public class HandleStores implements Client {
    private ArrayList observers;
    private double milkPrice;
    private double breadPrice;
    private double meatPrice;

    public HandleStores(){
        //All clients that want to be updated at the prices.
        observers = new ArrayList();
    }
    public void addClient(Observer newObserver) {
        observers.add(newObserver);
    }
    public void removeClient(Observer deleteMe) {
        int deleteIndex = observers.indexOf(deleteMe);
        System.out.println("Observer " + (deleteIndex+1) + " deleted");
        observers.remove(deleteIndex);
    }
    @Override
    public void notifyTheClients() {
        //Notify all the clients about the new prices.
        for(Observer o : observers){
            o.update(milkPrice, breadPrice, meatPrice);
        }
    }
    //Set the relevant price, and let everyone else now about the new price.
    public void setMilkPrice(double milkPrice) {
        System.out.println("Milk price has changed!");
        this.milkPrice = milkPrice;
        notifyTheClients();
    }
    public void setBreadPrice(double breadPrice) {
        System.out.println("Bread price has changed!");
        this.breadPrice = breadPrice;
        notifyTheClients();
    }
    public void setMeatPrice(double meatPrice) {
        System.out.println("Meat price has changed!");
        this.meatPrice = meatPrice;
       notifyTheClients();
    }
}

Main

public class main {
    public static void main(String [] args){

    /*Let's say that we have a few supermarkets that wishes to know some of their competitors prices,
      and match their prices according to the newest supermarket that has joined the app.
      At this project, we wil represent them as Clients of our app.
      They will be able to add client to our app,remove client and notify other companies about their prices.
      After they will register, and change the prices, they will use the update method of the ObserverPack.Observer interface,
      this method will update the values and print them to all the registered clients.
    */

        // Running example
        // Create the ObserverPack.Client object => HandleStore.
        // It will handle updating all clients as well as deleting and adding them.
        HandleStores handleStore = new HandleStores();
        StoreObserver observer1 = new StoreObserver(handleStore);
        handleStore.setMilkPrice(5.8);
        handleStore.setBreadPrice(4.7);
        handleStore.setMeatPrice(90.2);
        StoreObserver observer2 = new StoreObserver(handleStore);
        handleStore.setMilkPrice(10.00);
        handleStore.setBreadPrice(10.00);
        handleStore.setMeatPrice(20.00);

        // Delete one of the observers
        handleStore.removeClient(observer2);
        
        System.out.println("Manually changed prices:");
        handleStore.setMilkPrice(1.60);
        handleStore.setBreadPrice(2.00);
        handleStore.setMeatPrice(74.57);

        handleStore.removeClient(observer1);
    }
}

Running Example


New Client Observer 0
Milk price has changed!
Client number 0
 Milk: 5.8
 Bread: 0.0
 Meat: 0.0

Bread price has changed!
Client number 0
 Milk: 5.8
 Bread: 4.7
 Meat: 0.0

Meat price has changed!
Client number 0
 Milk: 5.8
 Bread: 4.7
 Meat: 90.2

New Client Observer 1
Milk price has changed!
Client number 0
 Milk: 10.0
 Bread: 4.7
 Meat: 90.2

Client number 1
 Milk: 10.0
 Bread: 4.7
 Meat: 90.2

Bread price has changed!
Client number 0
 Milk: 10.0
 Bread: 10.0
 Meat: 90.2

Client number 1
 Milk: 10.0
 Bread: 10.0
 Meat: 90.2

Meat price has changed!
Client number 0
 Milk: 10.0
 Bread: 10.0
 Meat: 20.0

Client number 1
 Milk: 10.0
 Bread: 10.0
 Meat: 20.0

Observer 2 deleted
Manually changed prices:
Milk price has changed!
Client number 0
 Milk: 1.6
 Bread: 10.0
 Meat: 20.0

Bread price has changed!
Client number 0
 Milk: 1.6
 Bread: 2.0
 Meat: 20.0

Meat price has changed!
Client number 0
 Milk: 1.6
 Bread: 2.0
 Meat: 74.57

Observer 1 deleted