Java built-in Observable push notifications

Tags: , ,



UPDATE Added the full code to make it easier to understand.

I am trying to understand how to implement push vs pull notifications using Java built-in Observer.

the Observable class has 2 methods notifyObservers() and notifyObservers(Object arg)

according to the docs: Each observer has its update method called with two arguments: this observable object and the arg argument.

here is my Observer class

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Observable observable;

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

    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and "
                + humidity + "% humidity");
    }

    @Override
    public void update(Observable o, Object arg) {
        /*
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
        }*/

        if (arg instanceof WeatherData) {
        WeatherData weatherData = (WeatherData) arg;
        this.temperature = weatherData.getTemperature();
        this.humidity = weatherData.getHumidity();
        }

        display();
    }

and in my observable class

public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    private void measurementsChanged() {
        setChanged();
        //notifyObservers();
        notifyObservers(this);
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

I’ve tried both methods, and both objects can be cast down to WeatherData(the Observer) and then get the data from them.

using both methods seem like push notification-type for me, so what is the difference? and how can I implement pull notification-type using it?

Answer

From the documentation of notifyObservers():

Each observer has its update method called with two arguments: this observable object and null. In other words, this method is equivalent to: notifyObservers(null)

That means that you should never call notifyObservers(this)—it’s redundant. Normally, the argument would be additional data about the change event. This is analogous to more modern event listener classes (Observable and Observer are now deprecated) whose events contain data in addition to the event source. For example, if you add an ActionListener to a button, pressing the button at runtime causes the ActionListener’s actionPerformed method to be called with an event that contains data such as the time when the action occurred.

A pull notification isn’t really a notification at all. Pulling means you don’t wait to be told that something changed; you ask whether anything has happened.

An example of this would be keeping a boolean field in your class that indicates whether any changes have occurred:

public class WeatherData {
    private boolean changed;

    // (other fields)

    public boolean checkForChanges() {
        boolean hasChanged = changed;
        // Now that someone has checked, reset the change flag
        changed = false;
        return hasChanged;
    }

    private void measurementsChanged() {
        changed = true;
        // Nothing else to do here.  Caller must "pull" (request) the
        // new state, by calling checkForChanges.
    }

As for how to do the pulling, just keep a reference to a WeatherData object in your CurrentConditionsDisplay class, and check whether it has changed:

public class CurrentConditionsDisplay implements DisplayElement { 

    private final WeatherData weatherData;

    public CurrentConditionsDisplay(WeatherData observable) {
        this.weatherData = observable;
    }

    @Override
    public void display() {
        // This is the pull.
        if (weatherData.checkForChanges()) {
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
        }

        System.out.println("Current conditions: " + temperature + "F degrees and "
                + humidity + "% humidity");
    }


Source: stackoverflow