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

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

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

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

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

Предлагаю ли я некоторые неприятные фальшивые проекты здесь?

Ответы

Ответ 1

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

Ответ 2

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

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

Ответ 3

Ковариантные типы возврата - это преднамеренная функция, которая была добавлена ​​в 1.5 (для поддержки в основном генериков).

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

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

Ответ 4

То, что вы делаете, полностью в порядке.

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

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

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

public interface ICoolCar extends ICar<ICoolEngine> { }

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