Problem with Observer Pattern and generics in Java

generics, java, observer-pattern

Solution

Try this:

 public class Observable<U> {

        private List<Observer<Observable<U>, U>> _observers =
                new ArrayList<Observer<Observable<U>, U>>();

        public void addObserver(Observer<Observable<U>, U> obs) {
            if (obs == null) {
                throw new IllegalArgumentException();
            }
            if (_observers.contains(obs)) {
               return;
            }
            _observers.add(obs);            }

        public void notifyObservers(U data) {
            for (Observer<? super Observable<U>, U> obs : _observers) {
                obs.atualizar(this, data);
            }
        }
    }

    interface Observer<T, U> {
        public void atualizar(T entity, U arg);
    }

To explain the underlying problem here, generics are forcing an explicit downcast. So you can't take any 'Observable' for any implementation of U and put it into a collection, because that collection is defined as taking a specific type of U, not anything.

For this type of use case, generics have limits, and you may not be able to accomplish what you want in such a type safe way.

EDIT: Would this work for you?

public class Observable<U> {

       private List<Observer<U>> _observers =
               new ArrayList<Observer<U>>();

       public void addObserver(Observer<U> obs) {
           if (obs == null) {
               throw new IllegalArgumentException();
           }
           if (_observers.contains(obs)) {
              return;
           }
           _observers.add(obs);            }

       public void notifyObservers(U data) {
           for (Observer<U> obs : _observers) {
               obs.atualizar(this, data);
           }
       }
   }

   interface Observer<U> {
       public void atualizar(Observable<U> entity, U arg);
   }

Problem

I have made a generic Observer interface and an Observable class, but can't compile my class due to some generics problem. I don't know precisely why what I'm trying to do is forbidden. The code follows: ``` public class Observable<U> { private List<Observer<Observable<U>, U>> _observers = new ArrayList<Observer<Observable<U>, U>>(); public void addObserver(Observer<? extends Observable<U>, U> obs) { if (obs == null) { throw new IllegalArgumentException(); } if (_observers.contains(obs)) { return; } _observers.add(obs); // This line does not compile } public void notifyObservers(U data) { for (Observer<? extends Observable<U>, U> obs : _observers) { // After correction of the list declaration, this line will not compile obs.update(this, data); } } } interface Observer<T, U> { public void update(T entity, U arg); } ```

Original source