DevDevDev
DevDevDev

Reputation: 5177

Best way to notify observers in MVC?

Say you have 5 or 6 variables in the model which a certain View is interested in, do you write different functions for each, such as

int a;
int b;
int c;

void setA( newA ) {
   a = newA;
   notifyAObservers();
}

void setB( newB ) {
   b = newB;
   notifyBObservers();
}

void setC( newC ) {
   b = newC;
   notifyCObservers();
}

Or do you just have one notify method and waste a little bit of CPU time

i.e. instead of notifyAObservers and notifyBObservers, you just have notifyObservers

Upvotes: 3

Views: 3278

Answers (2)

alexbt
alexbt

Reputation: 17065

EDIT: I wrote my answer a few years ago. After reading it just now, I felt I needed to update it.

I believe the best approach is to notify all observers and let the views decide if they need to update themselves..

Each view will be able to verify the state of the model and act accordingly. Additionally, the "args" could be used as a flag to indicate what has changed (the view may not wish to update itself for every little change).

That way, the model REALLY does not know how and what the view is displaying, they are decoupled.

A first implementation would look like this:

public class MyModelV1 extends Observable {
    private int value;
    public void setValue(int value) {
        this.value = value;
        setChanged();
        notifyObservers();
    }
    public int getValue() {
        return value;
    }
}
public class MyViewV1 implements Observer {
    public void update(Observable o, Object arg) {
        if (o instanceof MyModelV1) {
            System.out.println(((MyModelV1) o).getValue());
        }
    }
}

The view simply checks the type of the observable received. However, if the model has many attributes and triggers the view for many different scenarios, this simple check may refresh the view too often.

Another approach would be the following:

public class MyModelV2 extends Observable {
    private int value;
    public void setValue(int value) {
        this.value = value;
        setChanged();
        notifyObservers("value");
    }
    public int getValue() {
        return value;
    }
}
public class MyViewV2 implements Observer {
    public void update(Observable o, Object arg) {
        if (o instanceof MyModelV2 && "value".equals(arg)) {
            System.out.println(((MyModelV2) o).getValue());
        }
    }
}

Here, the notification passes a qualifier, which lets the view decide more precisely when to refresh itself. The view still needs to check and cast the Model, because there is no garantee that the arg "value" isn't notified by another model (and the cast would fail at runtime).

My personal favorite is something along those lines:

public class MyModelV3 extends Observable {
    private int value;
    public void setValue(int value) {
        this.value = value;
        setChanged();
        Notification.MY_MODEL_VALUE_UPDATED.notifyObserver(this);
    }
    public int getValue() {
        return value;
    }
}
public class MyViewV3 implements Observer {
    public void update(Observable o, Object arg) {
        if (Notification.MY_MODEL_VALUE_UPDATED.equals(arg)) {
            MyModelV3 model = Notification.MY_MODEL_VALUE_UPDATED.getModel(o);
            System.out.println(model.getValue());
        }
    }
}
public class Notification<T extends Observable> {
    public static final Notification<MyModelV3> MY_MODEL_VALUE_UPDATED = new Notification<MyModelV3>();
    private Notification() {
    }
    public T getModel(Observable o) {
        return (T) o;
    }
    public void notifyObserver(T observable){
        observable.notifyObservers(this);
    }
}

Here, the notification sends a strongly typed qualifier, which is bound to the Model. The view is able to use the notification to retrieve a strongly typed model (instead of casting).

This is somewhere between an observer and an event bus..

Upvotes: 0

Thomas Owens
Thomas Owens

Reputation: 116187

I believe the traditional approach is to notify all observers, and let them handle it. This is because you don't know which observers are observing which variable(s) - you just know that they want to be notified when something changes. However, if you do know what observers are observing which variables, and performance is critical, then you might be able to do something like what you have.

In the traditional Observer pattern, the Observers implement an update() method that is called by the controller when a change happens. The Observables (the data model) would have a notifyObservers() method that iterates over the Observers and calls their update() method. Then, the Observers get whatever they need and the view updates.

Any time I have implemented the Observer pattern, however, I simply keep a list of observers and notify them all. That way, I only have one list of observers and the rest of the class as well as the different observers can all change without me making any changes to the observable class notification.

Upvotes: 6

Related Questions