Переопределение метода с полиморфными аргументами

У меня есть интерфейс (называемый Subject), который имеет следующий метод:

public void addObserver(Observer o);

Затем у меня есть другой интерфейс, который расширяет Subject, называемый TimerSubject. Этот интерфейс является более конкретной версией Subject, используемой для синхронизации. У него есть несколько других разных методов.

Есть также два соответствующих интерфейса, Observer и TimerObserver. TimerObserver расширяет Observer.

Когда класс реализует TimerSubject, он должен переопределить метод addObserver() из интерфейса Subject. Это выглядит так:

@Override
public void addObserver(**Observer e**) {
    observers.add(e);
}

Проблема в том, что мне нужен метод для принятия TimerObserver вместо Observer, который будет выглядеть так:

@Override
public void addObserver(**TimerObserver e**) {
    observers.add(e);
}

Это не работает, поскольку аргументы не совпадают с аргументами переопределяемого метода.

Итак, есть ли способ переопределить метод с полиморфными аргументами?


person Ben Cracknell    schedule 05.04.2012    source источник


Ответы (2)


На ум приходит несколько решений:

Ваша реализация TimerSubject может реализовать public void addObserver (Observer), генерируя исключение RuntimeException, если он получает аргумент, не являющийся TimerObserver. Вы теряете защиту компилятора, навязывающего вам типы, но позднее связывание довольно типично для «истинного» полиморфизма.

В качестве альтернативы ваш интерфейс TimerSubject может просто указать новый метод addTimerObserver для нового поведения. Предположительно ваш TimerSubject расширяет тему, которая уже имеет реализацию addObserver(Observer); если эта реализация будет полностью несуществующей, вы можете переопределить и выдать ошибку. Но если TimerSubject действительно не использует метод addObserver(Observer) и этот метод полностью прекратил свое существование, то, возможно, эти два объекта не так полиморфны, как вам хотелось бы. :)

person Mike    schedule 05.04.2012

Однажды мне пришлось сделать что-то подобное, и в итоге я создал шаблон, т.е.

interface Subject<T extends Observer> {
 public void addObserver(T e);
}

class TimerSubject implements Subject<TimerObserver> {
 // ...
 @Override
 public void addObserver(TimerObserver e)
 {
  observers.add(e);
 }
}

Это сохраняет полиморфность метода addObserver и статически применяет тип аргумента.

Идея здесь в том, что если вы хотите, чтобы каждый конкретный реализатор интерфейса Subject добавлял разные типы Observers. Таким образом, вы заставляете интерфейс Subject запрашивать это. Имея универсальный класс T, расширяющий Observer, вы по-прежнему можете гарантировать, что люди, использующие метод addObserver, будут использоваться только для добавления Observer, что является бонусом. Таким образом, вы также можете написать полиморфный геттер, что-то вроде

public T getObserver(T e);

заполнение типов для любых производных классов. Сюда

Subject<?> foo = new TimerSubject();
// add observer somewhere
Observer bar = foo.getObserver();

также будет статически проверять тип. (Примечание: здесь я работаю с памятью, поэтому последний бит может быть не совсем правильным, но определенно есть какой-то способ сделать это так.)

person dcco    schedule 11.07.2013