This is an Observable
class similar to java.util.Observable
. The difference is that it uses generics to avoid casts. The question is: Is it really worth the effort? What are the problems with this code?
import java.util.ArrayList;
import java.util.Collection;
/**
* like java.util.Observable, But uses generics to avoid need for a cast.
*
* For any un-documented variable, parameter or method, see java.util.Observable
*/
public class Observable<T> {
private boolean changed = false;
// Holds registered observers.
// @TODO if class is not final can we make this protected? (should we?).
private final Collection<Observer<? super T>> observers;
/**
* observersSet gives the opportunity of changing the implementing set. The
* benefit is, final user can specify the 'order' of observers notified.
* Generally, not a good idea at all.
*
* @TODO should this be private and the class final?.
*/
protected Observable(Collection<Observer<? super T>> observersSet) {
this.observers = observersSet; }
public static <F> Observable<F>getInstance() {
// return getInstance(container);
ArrayList<Observer<? super F>> container = new ArrayList<>();
return new Observable<>(container);
}
/**
* Before this method can be actually used, this.update(T arg) must be fixed.
* It has a hard-coded ArrayList. Generally, not a good idea, not at all.
*
* User would expect the call getInstance(ArrayList<SomeObserver> ar) to
* work however it wont. It must be:
* getInstance(ArrayList<? extends SomeObserver> ar);
*
* It's bad, ugly, and more importantly, violating.
*
* Unless of course the first example could be made to work. Maybe a cast
* will do.
*/
@SuppressWarnings("UnusedParameters")
public static <F> Observable<F>
getInstance(Collection<Observer<? super F>> observersSet) {
throw new UnsupportedOperationException("Not yet implemented.");
// return new Observable<>(observersSet);
}
// @TODO null check maybe for add?
public synchronized boolean add(final Observer<? super T> o) {
return !this.observers.contains(o) && observers.add(o);
}
public void addObserver(final Observer<? super T> o) { this.add(o); }
public synchronized boolean rm(final Observer<? super T> o) { return observers.remove(o); }
public void deleteObserver(final Observer<? super T> o) { this.rm(o); }
public synchronized void clear() { this.observers.clear(); }
public void deleteObservers() { this.clear(); }
// @TODO all of them need synchronized?
public synchronized void setFlag() { this.changed = true; }
public synchronized void clrFlag() { this.changed = false; }
// Hei! did you know if you used projectLombok.org you could remove this
// method? didn't you?!!! :O 0_o
public synchronized boolean getFlag() { return this.changed; }
public boolean hasChanged() { return this.getFlag(); }
public int countObservers() { return this.observers.size(); }
public void update(final T args) {
ArrayList<Observer<? super T>> copy;
synchronized (this) {
if(!changed) return;
copy = new ArrayList<>(this.observers);
this.clrFlag();
}
// Look at OpenJDK to see why a new Collection is used.
for(Observer<? super T> o : copy) o.update(args);
}
public void notifyObservers(final T args) { this.update(args); }
public void update() { this.update(null); }
public void notifyObservers() { this.update(); }
}
Observable
now carries type of args
sent to each Observer
, and Observer
is also aware of it, thus no cast needed.
The follow up question is located here.
Observer
, it will help \$\endgroup\$Observer<EVENT>
andObserver<EVENT>
were interfaces. \$\endgroup\$