Как я могу получить правильное перечисление, которое реализует определенный интерфейс в Java? - PullRequest
0 голосов
/ 29 декабря 2018

У меня есть следующий интерфейс:

public interface Moon {
    // Enums can not extend any class in Java,
    // thus I am implementing an interface
    double getMass();
    double getDiameter();
}

, который реализуется моими перечислениями (я пропустил реализацию конструктора и методов)

public enum Saturn implements Moon {
    ATLAS(30.2, 6.6),
    PAN(28.2, 4.95);

    private double Diameter;
    private double Mass;

    // constructor and methods implementation
}

и аналогично перечислениям для других планет:

public enum Mars implements Moon {
    PHOBOS(22.2, 1.08),
    DEIMOS(12.6, 2);

    private double Diameter;
    private double Mass;

    // constructor and methods implementation
}

Вопрос

Имея две строки:

String planetName = "Mars";
String moonName = "PHOBOS";

Как получить определенное перечисление умным способом?

В случае только одного перечислимого класса это простое использование метода valueOf, но как я могу проверить все перечисления, которые реализуют определенный интерфейс?

Moon something = <??planetName??>.valueOf(moonName);

Ответы [ 5 ]

0 голосов
/ 02 января 2019

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

public enum Planets {
    MARS(Mars.values()), SATURN(Saturn.values());

    private final Enum<?>[] Moons;

    private Planets(final Enum<?>[] Moons) {
        this.Moons = Moons;
    }

    public Moon getMoon(final String moon) {
        return (Moon) Arrays
                .stream(this.Moons)
                .filter(e -> e.name().equals(moon))
                .findFirst()
                .get();
    }
}

. Он берет Луны из уже определенных перечислений и назначает их перечислению для каждой планеты.Существует также getMoon() (функция valueOf() уже используется самим enum), которая ищет луну.

Вы можете использовать ее следующим образом:

    // Outputs 22.2
    System.out.println("" + Planets.valueOf("MARS").getMoon("PHOBOS").getDiameter());
0 голосов
/ 29 декабря 2018

Если все ваши перечисления находятся в одном пакете, то это решение может работать.

String planetName = "Mars";
String moonName = "PHOBOS";

try {
    Moon moons[] = (Moon[]) Class.forName("your_package_name" + planetName).getEnumConstants();

    // The following line is not really needed, but I've added it as an 
    // illustration as to what you could do with the moons[]
    Moon planet = Arrays.stream(moons).filter(i -> i.toString().equals(moonName))
                          .findFirst().orElse(null);

} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
0 голосов
/ 29 декабря 2018

Если вы действительно хотите, чтобы он был динамичным, вы можете добиться этого с помощью Reflection, если я не рекомендую это сделать.Вы можете либо

0 голосов
/ 29 декабря 2018

Я подозреваю, что у вас есть слабость в вашем дизайне, которая заставляет вас искать сложные способы получения необходимого вам экземпляра enum.Наличие отдельного перечисления для каждой планеты, вероятно, не имеет большого смысла, когда все они являются уникальными лунами.Лучше немного переосмыслить дизайн.Что-то вроде:

interface Body {
    double getMass();
    double getDiameter();
}

enum Planet implements Body {
    MERCURY, VENUS...
}

enum Moon implements Body {
    ATLAS, PHOBOS, DEIMOS...

    public Planet getPlanet();
}

Таким образом, легко получить планеты или луны по имени.Или получите все луны планеты с:

Arrays.stream(Moon.values())
    .filter(m -> m.getPlanet().equals(this))
    ...
0 голосов
/ 29 декабря 2018

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

Например, используя карту (есть, безусловно, альтернативные подходы):

Map<String, Class<? extends Enum>> planetMoonTypes = new HashMap<>();

planetMoonTypes.put("Saturn", Saturn.class);
planetMoonTypes.put("Mars", Mars.class);

С такой картой вы можете найти значение "PHOBOS", используя:

Moon phobos = (Moon) Enum.valueOf(planetMoonTypes.get("Mars"), "PHOBOS");

Выше будет возвращено Mars.PHOBOS


РЕДАКТИРОВАТЬ: Относительно способности добавлять не лунные перечисления.Вы можете инкапсулировать карту и устанавливать правильные границы.Например, следующий метод использует для этого метод:

class MoonRegistry {

    private final Map<String, Class<? extends Enum>> 
              planetMoonTypes = new HashMap<>();

    {
        this.registerEnum("Saturn", Saturn.class);
        this.registerEnum("Mars", Mars.class);
    }

    public <T extends Enum<T> & Moon> void registerEnum(
            String planetName, Class<T> cls) {
        this.planetMoonTypes.put(planetName, cls);
    }

    public Moon findByPlanetAndName(String planet, String name) {
        return (Moon) Enum.valueOf(this.planetMoonTypes.get(planet), name);
    }
}

Опять же, это решение не может быть полностью безопасным с точки зрения типов, поскольку существует несколько подтипов enum (как вы можете видеть, тип raw Enum находится втип поля экземпляра).Но если это правильно инкапсулировано и ваш код не использует необработанные типы вне этого класса, вы можете убедиться, что добавляются только перечисляемые типы, реализующие Moon.

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