我有一系列看起来像这样的枚举,除了名称和值不同:
/* 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)
您可以使用最小化每个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针对每个类执行一次,使用该操作专门用于高效地缓存每类元数据,线程安全且不会在重要的环境中阻止类卸载.实际toDB和fromDB简化为哈希查找.
顺便说一句,这一点很重要,此代码使用getDeclaringClass(),而不是getClass()作为枚举可能有特喜欢在enum Foo { BAR { … } … }那里getClass()返回专业化类,而不是enum类型.