An Overview to Understand Observer Pattern in Java

You know how newspaper or magazine subscriptions work:

  1. A newspaper publisher  goes into business and begins publishing newspapers.
  2. You subscribe to particular publisher, and every time there’s a new edition it gets delivered to you. As long as you remain a subscriber, you get new newspapers.
  3. You unsubscribe when you don’t want papers anymore, and they stop being delivered.
  4. While the publisher remains in business, people, hotels, airlines, and other businesses constantly subscribe and unsubscribe to the newspaper.

PUBLISHERS + SUBSCRIBERS = OBSERVER PATTERN

You understand newspaper subscriptions, you pretty much understand the observer pattern, only we call the publishers the SUBJECT and the subscribers the OBSERVERS.

The Observer Pattern Defined

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

So far in last post, we saw about our own implementation code for the Observer Pattern in Java. But Java has built-in support in several of its API. The most general is the Observer interface and Observable class in the java.util.package. These are similar to our Subject and Observer interfaces defined in our post about Part I of Observer Pattern in Java.

How built-in Observer Pattern in Java works

The most obvious difference is that StockData(our Subject) now extends the Observable class and inherits the add, delete, and notify Observer methods.

For an Object to become an Observer…

As usual, implement the Observer interface from java.util.Observer and call the addObserver() on any Observable Object. Likewise, to remove yourself as an observer, just call deleteObserver().

For the Observables to send notifications…

First of all you need to be Observable by extending the java.util.Observable superclass. From there it is a two-step process.

Two-Step Process

  1. You first must call the setChanged() method to signify that the state has changed in your object.
  2. Then call one of two notifyObservers() method: either notifyObservers() or notifyObservers(Object arg)

For an Observer to receive notifications…

It implements the update method, as before, but the signature of the method is different,

update(Observable o, Object arg)

Now lets re-work the Stock Market App.

Re-working the Stock Market App with built-in Support

In StockData.java file check out the following things,

  1. Make sure we are importing the right Observable that is java.util.Observable
  2. We are now sub-classing the Observable
  3. The superclass will handle the track of managing the Observers (registering and removal)
  4. Our constructors don’t need to create a data structure to hold Observers
  5. We now first call setChanged() method to indicate the state has changed before calling notifyObservers() method which is a PULL model of notification.
import java.util.Observable;

public class StockData extends Observable {
  private float currentPrice;
  private float previousPrice;
  private float change;
  private float changePercentage;
  
  public StockData() {}
  
  public void stockRatesChanged() {
    setChanged();
    notifyObservers();
  }

  public void setStockRates(float currentPrice, float previousPrice, float change, float changePercentage) {
    this.currentPrice = currentPrice;
    this.previousPrice = previousPrice;
    this.change = change;
    this.changePercentage =changePercentage;
    stockRatesChanged();
  }
  
  public float getCurrentPrice() {
    return currentPrice;
  }

  public float getPreviousPrice() {
    return previousPrice;
  }

  public float getChange() {
    return change;
  }

  public float getChangePercentage() {
    return changePercentage;
  }
}

Now let’s rework the CurrentStockRateDisplay

In CurrentStockRateDisplay.java file check out the following things,

  1. Make sure we are importing right Observer/Observable
  2. We are implementing Observer interface from java.util
  3. In update() method, we first make sure is of type StockData and then we use its getter methods to obtain the values. After that we call display()
import java.util.Observable;
import java.util.Observer;

import com.observerpattern.DisplayElement;

public class CurrentStockRateDisplay implements Observer, DisplayElement {

  Observable observable;
  
  private float currentPrice;
  private float previousPrice;
  private float change;
  private float changePercentage;

  public CurrentStockRateDisplay(Observable observable) {
    this.observable = observable;
    observable.addObserver(this);
  }

  @Override
  public void update(Observable obs, Object arg) {
    if(obs instanceof StockData) {
      StockData stockData = (StockData)obs;
      this.currentPrice = stockData.getCurrentPrice();
      this.previousPrice =  stockData.getPreviousPrice();
      this.change =  stockData.getChange();
      this.changePercentage = stockData.getChangePercentage();
      display();
    }
  }

  public void display() {
    System.out.println("Company current price : "+currentPrice+" | previous price : "+previousPrice+" | change : "+change+" | change percentage : "+changePercentage);	

  }

}
public class StockMarket {

  public static void main(String[] args) {
    StockData stockData = new StockData();
    CurrentStockRateDisplay cd = new CurrentStockRateDisplay(stockData);

    stockData.setStockRates(40, 20, 10, 100);
    stockData.setStockRates(20, 10, 10, 100);
    stockData.setStockRates(15, 10, 5, 50);

  }
}

Output:

Company current price : 40.0 | previous price : 20.0 | change : 10.0 | change percentage : 100.0
Company current price : 20.0 | previous price : 10.0 | change : 10.0 | change percentage : 100.0
Company current price : 15.0 | previous price : 10.0 | change : 5.0 | change percentage : 50.0

Negatives of java.util.Observable

  1. As Observable is a class, you have to subclass it. That means you can’t add on the Observable behavior to an existing class that already extends another super class.
  2. As there isn’t an Observable interface, you can’t even create own implementation that plays well with Java’s built in Observer API.

Conclusion

Observable may serve your needs if you can extend java.util.Observable. On the other hand, you may also implement our own way of implementation if required as we are good to implement the pattern without the API’s.

Please follow and like us: