我有一系列的枚举,它们看起来像这样,除了名称和值是不同的:
/* 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;
}
}
我知道我不能扩展枚举,但有没有什么方法可以抽象这个设计,以删除每个类中toDB()、fromDB()和getText()中的所有重复代码?我研究了其他问题,比如Is it possible to extend enum in Java 8?,它有一个使用接口的示例,但我不知道如何处理构造函数和静态方法。我也不知道如何在fromDB()方法中删除对类型BoneDiagnosis的显式引用。
我的梦想是让每个类都像下面这样定义,所有其他的支持都封装在任何BoneDiagnosisComplexTypeDefinition中。这个是可能的吗?
public enum BoneDiagnosisComplexTypeDefinition {
NORMAL(121),
ELEVATED(207);
OSTEOPENIA(314),
OSTEOPOROSIS(315)
}
发布于 2017-09-08 07:00:59
您可以使用以下命令最小化每个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));
}
}
public enum BoneDiagnosis implements Common {
@DbId(121) NORMAL,
@DbId(207) ELEVATED,
@DbId(314) OSTEOPENIA,
@DbId(315) OSTEOPOROSIS;
}
测试用例
int id = BoneDiagnosis.OSTEOPENIA.toDB();
System.out.println("id = " + id);
BoneDiagnosis d = Common.fromDB(BoneDiagnosis.class, id);
System.out.println("text = " + d.getText());
请注意,使用ClassValue
对每个类只执行一次反射操作,这是专门为高效、线程安全地缓存每个类的元数据而设计的,并且不会在重要的环境中阻止类卸载。实际的toDB
和fromDB
被简化为散列查找。
顺便说一句,这段代码使用getDeclaringClass()
而不是getClass()
很重要,因为枚举可能具有像enum Foo { BAR { … } … }
中那样的专门化,其中getClass()
返回专门化类而不是enum
类型。
发布于 2017-09-08 04:27:19
这个解决方案仍然有一些样板桥接代码。
使用Interface
定义调用接口,并在某个类中实现公共代码。下面是一个简单的例子:
文件: BoneDiagnosis.java
public enum BoneDiagnosis
implements
CommonStuffs
{
NORMAL(121),
ELEVATED(207),
OSTEOPENIA(314),
OSTEOPOROSIS(315);
private CommonStuffsImpl commonStuffsImpl;
private int value;
BoneDiagnosis(final int theValue)
{
value = theValue;
commonStuffsImpl = new CommonStuffsImpl();
}
@Override
public int toDB()
{
return commonStuffsImpl.toDBImplementation(value);
}
}
文件: CommonStuffs.java
public interface CommonStuffs
{
int toDB();
}
文件: CommonStuffsImpl.java
public class CommonStuffsImpl
{
public int toDBImplementation(
final int value)
{
return value;
}
}
https://stackoverflow.com/questions/46104419
复制相似问题