Enums использует статический метод поиска

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

public enum MyEnum{
    A(10, "First"), //
    B(20, "Second"), //
    C(35, "Other options");

    private Integer code;
    private String description;

    private MyEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    public Integer getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }

    public static MyEnum getValueOf(Integer code) {
        for (MyEnum e : MyEnum.values()) {
            if (e.getCode().equals(code)) {
                return e;
            }
        }
        throw new IllegalArgumentException("No enum const " + MyEnum.class.getName() + " for code \'" + code
                + "\'");
    }
}

Что отлично работает. Метод getValueOf существует, потому что при общении с внешним партнером мы получаем только код (они выбрали) для сопоставления. Мне нужно описание, потому что мне нужно показать значащую фразу в графическом интерфейсе.

Но теперь у меня есть ряд подобных классов enum. Все они имеют свой собственный код и описание, и им нужны те же функции поиска. Я хотел, чтобы метод getValueOf был общим, поэтому мне не нужно поддерживать 30+ разных перечислений для одного и того же метода.

Чтобы решить эту проблему, я хотел создать абстрактный класс для определения этого метода и реализации некоторой общей логики, но это невозможно, потому что я не могу расширить Enum.

Затем я попытался создать класс Utility со следующим методом:

public static <T extends Enum<T>> T getValueOf(Enum<T> type, Integer code) {...}

Но generics с Enums запутывают, и я не понимаю, как это сделать.

В принципе, я хочу знать: что такое хороший подход для определения общей утилиты для перечисления?

Ответ 1

Вам необходимо передать фактический объект класса enum в качестве параметра для вашего метода. Затем вы можете получить значения перечисления с помощью Class.getEnumConstants().

Чтобы иметь возможность доступа к getCode() в экземплярах, вы должны определить его в интерфейсе и сделать все типы перечисления реализовать этот интерфейс:

interface Encodable {
    Integer getCode();
}

public static <T extends Enum<T> & Encodable> T getValueOf(Class<T> enumClass, Integer code) {
    for (T e : enumClass.getEnumConstants()) {
        if (e.getCode().equals(code)) {
            return e;
        }
    }
    throw new IllegalArgumentException("No enum const " + enumClass.getName() + " for code \'" + code
            + "\'");
}

...

public enum MyEnum implements Encodable {
    ...
}

MyEnum e = getValueOf(MyEnum.class, 10);

Ответ 2

Это немного сложно, потому что метод values() является статическим. Вам действительно понадобится отражение, но есть хороший способ скрыть это, используя стандартную библиотечную функциональность.

Сначала определите интерфейс с помощью методов, общих для всех типов перечислений:

public interface Common {
    Integer getCode();
    String getDescription();
}

Затем сделайте все свои перечисления реализующим этот интерфейс:

public enum MyEnum implements Common {...}

Статический метод, который вы хотите иметь, выглядит следующим образом:

public static <T extends Enum<T> & Common> T getValueOf( Class<T> type, Integer code ) {
    final EnumSet<T> values = EnumSet.allOf( type );
    for(T e : values) {
        if(e.getCode().equals( code )) {
            return e;
        }
    }
    throw new IllegalArgumentException( "No enum const " + type.getName() + " for code \'" + code + "\'" );
}