Является ли интерфейс, предоставляющий параметры для расширения параметризованного интерфейса, в Java точным его синонимом? - PullRequest
3 голосов
/ 21 октября 2019

Я хотел бы использовать интерфейс в качестве короткого имени для параметризованного интерфейса, чтобы избежать загрязнения всего кода общим синтаксисом. Например:

EggChicken egg = chicken.lay();  // Can't make it compile.

вместо:

Egg<AnimalChicken> egg = chicken.lay(); // Compiles happily.

Скажем, я хотел бы смоделировать режимы размножения животных, используя параметризованные классы (https://en.wikipedia.org/wiki/Modes_of_reproduction). У меня есть следующие интерфейсы:

public interface Animal<T> {
   T lay();
}

interface Viviparous<T extends Viviparous> extends Animal<T> {
}

interface Egg<T extends Oviparous> {
    T hatch();
}

interface Oviparous<T extends Oviparous> extends Animal<Egg<T>> {
}

Идея состоит в том, что живородящие животные откладывают новые экземпляры того же животного, тогда как яйцекладущие животные откладывают яйца, которые вылупляются новые экземплярыэтого же животного.

Теперь я хотел бы определить более точные интерфейсы для описания собаки и цыпленка:

interface AnimalDog extends Viviparous<AnimalDog> {
}

interface AnimalChicken extends Oviparous<AnimalChicken> {
}

interface EggChicken extends Egg<AnimalChicken> {
}

Наконец, это реализации:

public class AnimalDogImpl implements AnimalDog {
    @Override
    public AnimalDog lay() {
        return new AnimalDogImpl();
    }
}

class AnimalChickenImpl implements AnimalChicken {
    @Override
    public EggChickenImpl lay() {
        return new EggChickenImpl();
    }
}

public class EggChickenImpl implements EggChicken {
    @Override
    public AnimalChicken hatch() {
        return new AnimalChickenImpl();
    }
}

Моя проблема возникает, когда я хочу использовать классы в коде:

public class AnimalTest {
    @Test
    public void can_do_something_nice() {
        AnimalChicken chicken = new AnimalChickenImpl();
        // Error here:
        EggChicken egg = chicken.lay();
        AnimalChicken chick = egg.hatch();
       Assertions.assertThat(chick).isNotNull();
    }
}

Я получаю ошибку: Обязательный EggChicken, найдено Egg , но этокак именно я определил EggChicken. Можно ли решить этот тип косвенного обращения?

Ответы [ 2 ]

5 голосов
/ 21 октября 2019

То, что вы ищете, называется псевдонимом типа .

У Java, к сожалению, их нет.

Когда вы создаете новый интерфейс, он определяет новый тип. Экземпляр EggChicken также является экземпляром Egg<Chicken>, но не наоборот. Вам придется заставить ваш AnimalChicken (интерфейс!) Явно возвращать EggChicken.

0 голосов
/ 21 октября 2019

Общая идея верна, но в иерархии есть проблемы. Animal не может напрямую заложить тип, который является Egg или Animal, они не связаны. Я думаю, что следующее представляет то, что вы намеревались:

    interface LayProduct {}

    interface Animal<E extends LayProduct> extends LayProduct{
        E lay();
    }

    interface Egg<E extends Egg<E,A>, A extends Oviparous<E,A>> extends LayProduct {
        A hatch();
    }

    interface Viviparous<A extends Viviparous<A>> extends Animal<A> {    }

    interface Oviparous<E extends Egg<E,A>, A extends Oviparous<E,A>> extends Animal<E> {    }


    interface AnimalDog extends Viviparous<AnimalDog> {
    }

    interface AnimalChicken extends Oviparous<EggChicken,AnimalChicken> {
    }

    interface EggChicken extends Egg<EggChicken,AnimalChicken> {
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...