#java #generics #wildcard
#java #дженерики #подстановочный знак
Вопрос:
У меня есть объявление класса, в котором используются общие и ограниченные подстановочные знаки:
class Factory<T extends Logic<? extends Entity>,
U extends DAO<? extends Entity>>
{
}
По сути, это универсальная фабрика, которая принимает логический интерфейс (T) и возвращает настроенную реализацию. Для создания экземпляра логики я беру соответствующий класс DAO, реализующий интерфейс DAO (U).
Оба интерфейса для logic и DAO также являются общими и принимают тип объекта для работы в качестве параметра типа. Однако я хочу ограничить это еще больше, чтобы DAO и Logic не только имели параметр типа, который расширяет Entity, но и расширяли одну и ту же сущность. Результат может выглядеть примерно так:
class <X extends Entity> Factory<T extends Logic<X>,
U extends DAO<X>>
{
}
Могу ли я достичь этого с помощью Java generics?
Ответ №1:
Да, вы близки к цели. Сделайте это следующим образом:
class Factory<X extends Entity,
T extends Logic<X>,
U extends DAO<X>>
{
}
Альтернатива
class Factory<T extends Logic<?>,
U extends DAO<?>>
{
// Here, the generic method parameter only requires X
// to be the same bound at method invocation. However,
// you will "lose" that information again when the
// Factory is returned.
public static <X extends Entity,
T extends Logic<X>,
U extends DAO<X>> Factory<T, U> createFactory(T logic, U dao)
{
return new Factory<T, U>(logic, dao);
}
}
Комментарии:
1. Вы также должны сделать это, если у вас этого еще нет:
interface Logic<T extends Entity>
.2. Я думаю, вы пропустили там запятую после объекта. Ваше решение будет работать, но нет ли решения, в котором мне не нужно вводить параметр третьего типа? Ваша версия Factory будет создана следующим образом:
Factory<MyEntity, MyLogic, MyDAO> = new Factory<MyEntity, MyLogic, MyDAO>();
— верно? @ Thomas: Параметр типа Logic / DAOs уже ограничен, вот почему я чувствую, что дополнительный параметр типа в Factory для отношения излишен.3. Это зависит. Смотрите мой вариант. Там вы можете потребовать, чтобы
X
была одинаковая привязка для обоихLogic
иDAO
. Но как только вы сделаете ссылкуFactory
, вы, конечно, снова потеряете эту информацию, если она не будет помещена в сам классFactory
…4. @atamanroman Проблема в том, что универсальные типы не могут ссылаться на универсальные параметры друг друга, но вы все равно захотите передать один и тот же класс сущностей, а не что-то вроде
Factory<Logic<FooEntity>, DAO<BarEntity>>
ifFooEntity
иBarEntity
не связаны.
Ответ №2:
Другим подходом могло бы быть предоставление оболочки (хотя это не совсем элегантно ;)):
class Entity{}
interface Logic<T extends Entity> {}
interface DAO<T extends Entity> {}
interface DaoLogic<X extends Entity> {
DAO<X> getDAO();
Logic<X> getLogic();
}
class Factory<T extends DaoLogic<? extends Entity>> {}
Ответ №3:
Сработает ли следующее. X был бы «общим» типом, где Logic и DAO оба использовали бы этот тип.
public class Factory<X extends Entity, T extends Logic<X>, U extends DAO<X>>
{
}