I'm going to use Java for code/idea demonstration.
Imagine it's needed to define two interfaces: Observer and Observable (observer pattern). It's a good idea to have two generic interfaces, so there is no restriction on what is being observed, who is observing it (is even using generics about this?).
Java has a concrete (non-final) Observable class and an Observer interface. You have to delegate handling observers and notifying them on update to the concrete Observer class. This is one way of implementing the pattern. I don't know if it's the best approach (probably is), but for the sake of this example let's assume every class/type who wants to be observable, must implement the Observable interface below, and handle everything itself.
We should not forget the original Observer and Observable interface/object were implemented in JDK1.0, when generics were not available.
Now the question: Is this a good idea to merely declare a generic type in an interface to denote that the implementing class needs to be aware of some specific type? Or it is totally wrong way of using generics?
See:
public interface Observable<T> {
// Only observers who are aware of type T are allowed.
// But should really Observable be concerned about it?
public void registerObserver(Observer<? extends T> o);
}
// The T here denotes that implementing class will be aware of a type called T,
// (not that it can operate on a range of types).
public interface Observer<T> {
// Observer is not aware of Observable interface directly. But it knows about T.
public void update(T arg);
}
VS
public interface Observable {
// Is it an observer? then it is allowed. That's all we need to know.
public void registerObserver(Observer o);
// Observers will be passed the instance of observable,
// then they call this method to fetch arg.
// something like:
// for(Observer o: this.observers) o.update(this);
public <T> T getArg();
}
public interface Observer {
// Pass me an Observable who returns T and i'll do the rest!
public void update(Observable o);
}
I feel I'm getting generics totally wrong.
P.S: Comparing this way of implementing the observer pattern (asking every type to re-implement these interfaces) vs the original java solution (delegation) we realize it's not really a good idea. It causes a lot of code duplicate. But it helps to understand generics better.
Update The actual problem with java.util.Observer
is notifyObservers(Object arg)
[link to doc] where arg
is cast at runtime by observers. How can we avoid such cast?
Observable<T>
be aware of typeT
?class SomeBadlyNamedHandler implements Observer<Thing>
... the observed object is a Thing and can just work with it as such. The second example will force you to state the type when you getArgThing t = observer.getArg()
However, I think the second example will create a warning or error, because you're losing type information in theupdate
signature. General answer below; might have to try it both ways & see what looks best.