I implemented a simple observer pattern using generics in Java.
Anyway, now the example works only because the update
method of the ConcreteObserver is implemented with the .toString()
method that is common to all objects.
In a real world case, the ConcreteObserver only operates on a specific type of data. For example, if my ConcreteObserver is a player, it can plays .mp3 or .avi but not .doc.
Which is the correct way to "force" a specific kind of data to be passed as a contract between Observer and Observable? Generics is too generic...
In the case of method signatures, I can use Interfaces to force the implementation of a specific signature.
Which is the way I can force a specific data type passed?
For example: I want a kind of data composed of:
- a string
- an int (the length of the next binary data block)
- a a block of binary data
- some kind of metadata descriptor of the binary block
I want this kind of data interface the only allowed.
Here is the code where I use generics.
public interface Observable<T> {
public void add(Observer<T> observer);
public void remove(Observer<T> observer);
public void sendNotify(T notification);
}
public class ConcreteObservable<T> implements Observable<T> {
ArrayList<Observer<T>> observerList = new ArrayList<>();
public void add(Observer<T> observer){
observerList.add(observer);
}
public void remove(Observer<T> observer) {
observerList.remove(observer);
}
public void sendNotify(T notification) {
for (Observer observer : observerList) {
observer.update(notification);
}
}
}
public interface Observer<T> {
public void update(T value);
}
public class ConcreteObserver<T> implements Observer<T> {
@Override
public void update(T value) {
System.out.println(value.toString());
}
}
public static void main(String[] args) {
ConcreteObservable observable = new ConcreteObservable();
ConcreteObserver observer = new ConcreteObserver();
observable.add(observer);
int value = 5;
observable.sendNotify(value);
String string = "Test";
observable.sendNotify(string);
}