多个Java 8枚举使用相同的方法

sim*_*ser 1 java enums java-8

我有一系列看起来像这样的枚举,除了名称和值不同:

/* Bone Diagnosis. Value is internal code stored in database. */
public enum BoneDiagnosis {
    NORMAL(121),
    ELEVATED(207),
    OSTEOPENIA(314),
    OSTEOPOROSIS(315);

    private int value;
    BoneDiagnosis(final int value) {
        this.value = value;
    }

    /** Get localized text for the enumeration. */
    public String getText() {
        return MainProgram.localize(this.getClass().getSimpleName().toUpperCase() + ".VALUE." + this.name());
    }

    /** Convert enumeration to predetermined database value. */
    public int toDB() {
        return value;
    }

    /** Convert a value read from the database back into an enumeration. */
    public static BoneDiagnosis fromDB(final Integer v) {
        if (v != null) {
            for (final BoneDiagnosis pc : values()) {
                if (v == pc.toDB()) {
                    return pc;
                }
            }
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道我不能扩展枚举,但有没有办法抽象这个设计来删除每个类有的toDB(),fromDB()和getText()中的所有重复代码?我查看了其他问题,例如是否可以在Java 8中扩展枚举?有一个使用接口的例子,但我无法弄清楚如何处理构造函数和静态方法.我也无法弄清楚如何在fromDB()方法中删除显式引用类型BoneDiagnosis.

我的梦想是让每个类只被定义为下面的内容,所有其他支持都包含在BoneDiagnosisComplexTypeDefinition中.这可能吗?

public enum BoneDiagnosisComplexTypeDefinition {
    NORMAL(121),
    ELEVATED(207);
    OSTEOPENIA(314),
    OSTEOPOROSIS(315)
}
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 5

您可以使用最小化每个enum代码和每个操作的开销

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
public @interface DbId {
    int value();
}
final class Helper extends ClassValue<Map<Object,Object>> {
    static final Helper INSTANCE = new Helper();

    @Override protected Map<Object, Object> computeValue(Class<?> type) {
        Map<Object,Object> m = new HashMap<>();
        for(Field f: type.getDeclaredFields()) {
            if(f.isEnumConstant()) try {
                Object constant = f.get(null);
                Integer id = f.getAnnotation(DbId.class).value();
                m.put(id, constant);
                m.put(constant, id);
            }
            catch(IllegalAccessException ex) {
                throw new IllegalStateException(ex);
            }
        }
        return Collections.unmodifiableMap(m);
    }
}
public interface Common {
    String name();
    Class<? extends Enum<?>> getDeclaringClass(); 
    default int toDB() {
        return (Integer)Helper.INSTANCE.get(getDeclaringClass()).get(this);
    }
    default String getText() {
        return MainProgram.localize(
            getDeclaringClass().getSimpleName().toUpperCase() + ".VALUE." + name());
    }
    static <T extends Enum<T>&Common> T fromDB(Class<T> type, int id) {
        return type.cast(Helper.INSTANCE.get(type).get(id));
    }
}
Run Code Online (Sandbox Code Playgroud)
public enum BoneDiagnosis implements Common {
    @DbId(121) NORMAL,
    @DbId(207) ELEVATED,
    @DbId(314) OSTEOPENIA,
    @DbId(315) OSTEOPOROSIS;
}
Run Code Online (Sandbox Code Playgroud)

测试示例

int id = BoneDiagnosis.OSTEOPENIA.toDB();
System.out.println("id = " + id);
BoneDiagnosis d = Common.fromDB(BoneDiagnosis.class, id);
System.out.println("text = " + d.getText());
Run Code Online (Sandbox Code Playgroud)

请注意,反射操作仅ClassValue针对每个类执行一次,使用该操作专门用于高效地缓存每类元数据,线程安全且不会在重要的环境中阻止类卸载.实际toDBfromDB简化为哈希查找.

顺便说一句,这一点很重要,此代码使用getDeclaringClass(),而不是getClass()作为枚举可能有特喜欢在enum Foo { BAR { … } … }那里getClass()返回专业化类,而不是enum类型.