Проблема с шаблоном Observer и дженериками в Java - PullRequest
4 голосов
/ 09 июля 2009

Я создал универсальный интерфейс Observer и класс Observable, но не могу скомпилировать мой класс из-за какой-то проблемы с обобщениями. Я не знаю точно, почему то, что я пытаюсь сделать, запрещено. Код следует:

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);
}

Ответы [ 2 ]

6 голосов
/ 09 июля 2009

Измените определение _observers следующим образом:

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

Если вы хотите разрешить подклассы, вам нужно указать это в объявлении, а не только в том месте, где вы его используете

3 голосов
/ 09 июля 2009

Попробуйте это:

 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);
    }

Чтобы объяснить основную проблему здесь, дженерики вызывают явное снижение. Таким образом, вы не можете взять Observable для любой реализации U и поместить его в коллекцию, потому что эта коллекция определяется как принимающая определенный тип U, а не что-либо.

Для этого типа использования у дженериков есть ограничения, и вы, возможно, не сможете выполнить то, что вы хотите, таким безопасным способом.

РЕДАКТИРОВАТЬ: Это будет работать для вас?

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);
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...