Переопределение возвращаемого типа в расширенном интерфейсе - Плохая идея?
В 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 +