Переопределение типа возвращаемого значения в расширенном интерфейсе - плохая идея? - PullRequest
15 голосов
/ 14 мая 2009

В Java вы можете сделать следующее:

public interface IEngine{}
public interface ICoolEngine extends IEngine{}

public interface Car
{
   IEngine getEngine();
}
public interface ICoolCar extends ICar
{
    @Override
    ICoolEngine getEngine();
}

Хотя это хорошо решает проблему, с которой я столкнулся, что-то в этом "кажется" неправильным.

Я совершаю здесь какие-то мерзкие замыслы?

Ответы [ 4 ]

15 голосов
/ 14 мая 2009

Нет, вы делаете правильные вещи. Возвращаемые значения Covariant просто указывают, что класс и классы ниже него должны возвращать определенный подкласс исходного аргумента общего класса, который возвратил родительский класс. Это также означает, что ваши подклассы по-прежнему совместимы с исходным интерфейсом, который требует, чтобы он возвращал Engine, но если вы знаете , что это ICoolCar, у него есть ICoolEngine - потому что более конкретный интерфейс знает о более конкретный функционал. Это относится как к интерфейсам, так и к классам - это правильно, правильно и полезно для загрузки.

3 голосов
/ 14 мая 2009

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

Это неплохая практика; вы просто используете силу полиморфизма.

2 голосов
/ 14 мая 2009

Ковариантные типы возвращаемых данных - это преднамеренная функция, которая была добавлена ​​в 1.5 (в первую очередь для поддержки обобщений).

@ Переопределение может не работать для переопределения абстрактных методов с некоторыми компиляторами (javac был обновлен в 1.6, но поправка JLS была пропущена).

Как всегда, добавление метода в интерфейс сопряжено с риском совместимости. Переназначение метода точно так же, как в супертипе, было бы хорошо, но изменение возвращаемого типа вызывает метод моста в классах реализации. Вот почему Iterable.iterator не возвращает версию интерфейса Iterator только для чтения.

0 голосов
/ 14 мая 2009

То, что вы делаете, совершенно нормально.

Я бы предпочел сказать так:

public interface IEngine { }
public interface ICoolEngine extends IEngine { }

public interface ICar<T extends IEngine> {
   T getEngine();
}

public interface ICoolCar extends ICar<ICoolEngine> { }

Я использовал дженерики, потому что, как вы использовали аннотацию, я догадался, что вы работаете над Java 5 +

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