Java: замена подкласса / подтипа параметра при переопределении метода? - PullRequest
8 голосов
/ 11 декабря 2010

Итак, я задавал этот вопрос раньше, но у меня была ошибка в коде, который воспринял большинство людей, а не сама проблема.

В любом случае, я пытаюсь переопределить интерфейсный метод в классе. Однако я хочу, чтобы тип параметра в методе переопределения был подклассом типа параметра, определенного в методе переопределения.

Интерфейс:

public interface Observer {
 public void update(ComponentUpdateEvent updateEvent) throws Exception;
}

В то время как класс, который переопределяет этот метод:

public class ConsoleDrawer extends Drawer {

//...

 @Override
 public void update(ConsoleUpdateEvent updateEvent) throws Exception {
  if (this.componentType != updateEvent.getComponentType()) {
   throw new Exception("ComponentType Mismatch.");
  }
  else {
   messages = updateEvent.getComponentState(); 
  }
 }

//...

}

ConsoleUpdateEvent является подклассом ComponentUpdateEvent.

Теперь я мог бы просто заставить метод update () в ConsoleDrawer принять ComponentUpdateEvent в качестве параметра и затем преобразовать его в ConsoleUpdateEvent, но я ищу, по возможности, более элегантное решение. Любая помощь будет оценена. Спасибо.

Ответы [ 3 ]

8 голосов
/ 11 декабря 2010

Вы не можете.Это не Эйфелева.Проблема в том, что вы можете использовать интерфейс для вызова метода реализации несовместимого типа.Поэтому ковариантные параметры не допускаются.Контравариантные параметры также недопустимы, но легче обеспечить перегрузку.Разрешен ковариантный тип возврата (начиная с 1.5).

Вы можете параметризовать интерфейс:

public interface Observer<T extends ComponentEvent> {
    void update(T event) throws Exception;
}

В качестве альтернативы, используйте более значимый интерфейс:

public interface ConsoleObserver {
    void update(ConsoleEvent event) throws Exception;
}
2 голосов
/ 18 апреля 2014

Исходя из принципов ООП, подкласс должен использоваться точно так же, как родительский класс.например,

Observer ob = new ConsoleDrawer();
ob.update(new ComponentUpdateEvent()); // This needs to work always.

Однако, если бы Java позволяла вам использовать подтип параметра при переопределении метода, тогда ваш код подвергался бы случаям, когда переопределяющий метод (в подклассе) отклонялвходной параметр (ComponentUpdateEvent в приведенном выше случае).Таким образом, вы никогда не будете уверены, безопасно ли вызывать update () или нет по ссылке Observer.

Следовательно, единственное логическое решение - принять параметр родительского класса, проверить его тип и затем привести его к требуемому подтипу.

2 голосов
/ 11 декабря 2010

Вы можете попробовать следующее.@Deprecated выдает предупреждение, если компилятор знает, что вы будете вызывать первый метод, а не второй.

@Override @Deprecated
public void update(ComponentUpdateEvent updateEvent) {
    // throws a ClassCastException if its not the right type.
    update((ConsoleUpdateEvent) updateEvent); 
}

public void update(ConsoleUpdateEvent updateEvent) {
    messages = updateEvent.getComponentState(); 
}

Кстати: вы не должны просто помещать throws Exception на все.Это, безусловно, не лучшая практика.

РЕДАКТИРОВАТЬ: Я реализовал другое решение этой проблемы, которое хорошо работает с OSGi, но может работать где угодно.

Обозреватель регистрирует себя у брокера и ожидает найтиметоды с аннотацией, такой как ObserverCallback.

например,

public class ConsoleDrawer extends Drawer {
 @ObserverCallback
 public void onConsoleUpdateEvent(ConsoleUpdateEvent updateEvent) {
   messages = updateEvent.getComponentState(); 
 }
}

public class DeviceDrawer extends Drawer {
 @ObserverCallback
 public void onDeviceUpdateEvent(DeviceUpdateEvent updateEvent) {
   // do something.
 }
}

В первом случае посредник находит метод с @ObserverCallback, который принимает один аргумент.Это единственный тип, который Брокер передаст.Второй класс ожидает другого типа.Наблюдатели могут иметь несколько методов / типов, что позволяет им обрабатывать разные сообщения различными методами, подходящими для этого типа.Вы также знаете, что никогда не получите тип данных, который вы не ожидаете.

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