0

hi guys, I've come across observers while working ona very very large project, and I didn't quite understand how they were structured and I suppose this had something to do with the huge size of the project itself.
Anyway, I then decided to delve a little more into that, I had a look in a few places, believe I understand more or less the theory and wrote some code - well in fact it's code that I got from a few places, play with it a little bit and then pretty much re wrote it again..
So, to my question now: could someone cast an eye on it and:
1)let me know if it makes sense (it works as expected
2)is that it? Does it, although very simplistically, represent the meaning and purpose of what the observer pattern is meant to be used for?
3)any suggestiong as to it can be improverd, expanded etc
The code is pretty simple, there is a bankAccount object - the Observable - and then I created a few Observers using a loop - the number is fixed to 7 in my example. The test class creates the Observable objects passing the Observable as a parameter to it, then it adds the observers to the list of observers and changes the Observable triggering the update method. that's it.
Here is the code:

//the observable
import java.util.Observable;

public class BankAccount extends Observable
{

    private int balance = 0;

    public BankAccount(int balance)
    {
        this.balance = balance;
    }

    public int getBalance()
    {
        return balance;
    }

    public void setBalance(int balance)
    {
        this.balance = balance;
        setChanged();//set the flag to indicate that this observable has changed
        notifyObservers();//notify everyone
    }
}

//the Testing class
import java.util.ArrayList;
import java.util.Observer;

public class TestObserver
{

    public static void main(String[] args)
    {
        ArrayList<Observer> users = new ArrayList<>();
        BankAccount bankAccount = new BankAccount(1);
        int observerNum = 7;
        for(int i = 0; i < observerNum; i++){
            BankAccountObserver bankAccountObserver = new BankAccountObserver(bankAccount);
            users.add(bankAccountObserver);
        }
        for(Observer user : users){
            bankAccount.addObserver(user);
        }
        bankAccount.setBalance(22);
    }

}

//the Observer(s)
import java.util.Observable;
import java.util.Observer;

public class BankAccountObserver implements Observer
{

    private BankAccount bankAccount = null;

    public BankAccountObserver(BankAccount bankAccount)
    {
        this.bankAccount = bankAccount;
    }
    @Override
    public void update(Observable o, Object arg)
    {
        if (o == bankAccount)
          {
            System.out.println("BankAccountObserver balance: " + bankAccount.getBalance());
          }

    }

}
2
Contributors
3
Replies
25
Views
3 Months
Discussion Span
Last Post by JamesCherrill
0

Yes, that's it. It really is that simple.
But it's power to simplify structure is vast - it changes what would be a two-way dependency to a one-way dependency. That means you can build your code in layers, each needing zero knowledge of tha layers above it, even when events flow upwards at run time. Eg a user interface "observing" a business model.

The only annoying thing in the Java API version is that Observable is a class so if you want to use it you can't extend any of your own classes (no multiple inheritance). So in practice you end up copy/pasting the code for observable into all your classes that need it. Maybe in Java 8 it could be replaced by an interface with default methods? (note to self: have a look at that).

ps: Observable and Observer have been deprecated in Java 9, so their days are numbered.

Edited by JamesCherrill

0

Cool, thanks.

The only annoying thing in the Java API version is that Observable is a class so if you want to use it you can't extend any of your own classes (no multiple inheritance)

Yes I was actually wondering about this when I started witht he above code. However you can create, presumably, your own Observer interface with the methods you want to implement? But that should be independent from the java version used.

0

Yes. I did look at it and it's possible to create an interface using default methods that gives you a working listener add-in. (Requires Java 8 or later, but nobody should be risking their lives with any earlier version today.) The only tacky thing about it is that you can't define an instance variable in an interface, so to hold the list of listeners for each Observable I created a static Map with the Observable instance as key as its listeners as value.
It's far from polished, just w.i.p., but for what it's worth here it is... (I changed the names a bit to avoid confusion)

interface ChangeListener {

    // called in each listener when the notifer has changed state
    default void hasChanged(Object source) {
        // override to do something more than just test the call
        System.out.println(this + " received change notification from " + source);
    }
}

interface ChangeNotifier {

    Map<ChangeNotifier, List<ChangeListener>> listenerMap = new HashMap<>();

    default void addListener(ChangeListener listener) {
        synchronized (listenerMap) {
            List<ChangeListener> listeners = listenerMap.get(this);
            if (listeners == null) {
                listeners = new ArrayList<>();
                listenerMap.put(this, listeners);
            }
            listeners.add(listener);
        }
    }

    default void removeListener(ChangeListener listener) {
        synchronized (listenerMap) {
            List<ChangeListener> listeners = listenerMap.get(this);
            if (listeners == null) return;
            listeners.remove(listener);
        }
    }

    default void notifyListeners() {
        List<ChangeListener> listeners = listenerMap.get(this);
        if (listeners == null) return;
        ListIterator<ChangeListener> li = listeners.listIterator();
        while (li.hasNext()) {
            li.next().hasChanged(this);
        }
    }
}

so now to implement this in a class you just declare it as implements ChangeListener and call notifyListeners() whenever necessary.

Edited by JamesCherrill

Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.