I was looking to implement an subject-observer pattern where the subject provides its self to the observers when notifying.
public class Subject<T extends Subject> {
/** suporting stuff for subject */
private List<Observer<T>> observers = new ArrayList<>();
protected void doNotify() {
for(Observer<T> observer : observers) {
/** This is the line where it gets interesting */
observer.update((T)this);
}
}
}
Practically, this work, however, the compiler gives a Unchecked cast warning on the observer.update((T)this); line.
When reading a bit about this, the compiler is right (surprise surprise) and its even considered as smelly code, as you can write code that actually triggers the ClassCastException.
Now I am looking for a solution that isn't smelly and rock solid. However, the thought that an observer does not need to look for the subject that it is observing is something I really like. Also, I don't really like the observers need to do the cast themselves in their update(). Do you have any suggestion on how to on this one?
Edit
My observer is declared as interface like this:
public interface Observer<T> {
void update(T subject);
}
Foreword: I would suggest NOT to use generics- because by forcing the clients (Observers) to know about the exact type of a Subject, (as opposed to having a non-generic Subject class), you cannot eg. subscribe the same Observer to multiple Subjects (of different types).
Anyway, there is a way to have type-safety .
In the call
observer.update((T)this)you want two things: you want to passthisto observers; and you also want forthisto be of typeT.At that point,
thisis not guaranteed to be of typeTof course- it is of type Subject. But "this" will be of type T in a concreteSubjectclass. So substitutethiswithgetThisSubject()and move it down in the hierarchy. In code:Let me stress that we are coupling
Observertypes withSubjecttypes; they really are in a one-to-one relationship. A way to avoid this is declaringSubjectnon-generic, andplus using visitor or other patterns. (but this reply is long enough already).