[英]How to genericize a Java enum with static members?
我正在重构遗留应用程序的一部分,该应用程序处理从/到Excel工作表的数据库表的导出和导入。 我们为每个表都有一个Formatter
子类,以提供该表的定义:它具有多少列,以及每列的名称,格式和验证器是什么。 然后,通过导出/导入表的模板方法调用提供此数据的吸气剂。 我已经将列数据提取到一个枚举中,这大大简化了代码。 格式化程序现在看起来像这样(为简洁起见,省略了一些详细信息):
public class DamageChargeFormatter extends BaseFormatter {
public static final int NUM_COLUMNS = 7;
public enum Column {
VEHICLE_GROUP(0, "Vehicle Group", /* more params */),
NAME_OF_PART(1, "Name of Part", /* more params */),
//...
LOSS_OF_USE(6, "Loss of Use", /* more params */);
private static final Map<Integer, Column> intToColumn = new HashMap<Integer, Column>();
static {
for (Column type : values()) {
intToColumn.put(type.getIndex(), type);
}
}
public static TableColumn valueOf(int index) {
return intToColumn.get(index);
}
private int index;
private String name;
Column(int index, String name, /* more params */) {
this.index = index;
this.name = name;
//...
}
public int getIndex() { return index; }
public String getName() { return name; }
// more members and getters...
}
protected String getSheetName() {
return "Damage Charges";
}
public String getColumnName(int columnNumber) {
TableColumn column = Column.valueOf(columnNumber);
if (column != null) {
return column.getName();
}
return null;
}
// more getters...
protected int getNumColumns() {
return NUM_COLUMNS;
}
protected boolean isVariableColumnCount() {
return false;
}
}
现在,我大约有十二个这样的类,除了NUM_COLUMNS
和Column
的枚举值不同之外,每个类都包含完全相同的代码。 有什么办法可以某种方式将其泛化吗? 这样做的主要障碍是静态Column.valueOf()
方法和静态常量NUM_COLUMNS
。 后者的另一个担心是,它确实属于更高一级的抽象,即属于表,而不是单个列-最好以某种方式将其合并到通用解决方案中。
从技术上讲,我可以使用基本接口(下面的TableColumn
)和反射来解决此问题,但是我不是很喜欢,除了将编译时错误换成运行时错误外,这对我来说代码也很丑陋:
public class GenericFormatter<E extends TableColumn> extends BaseFormatter {
private Method valueOfMethod;
public GenericFormatter(Class<E> columnClass) {
try {
valueOfMethod = columnClass.getDeclaredMethod("valueOf", Integer.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public String getColumnName(int columnNumber) {
try {
@SuppressWarnings("unchecked")
E elem = (E) valueOfMethod.invoke(columnNumber);
if (elem != null) {
return elem.getName();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
//...
}
请注意,此代码纯粹是实验性的,尚未经过测试...
有没有更好,更清洁,更安全的方法?
可能是这样的:
public class TableMetadata<E extends Enum & TableColumn> {
private Map<Integer, TableColumn> columns = new HashMap<Integer, TableColumn>();
public TableMetadata(Class<E> c) {
for (E e: c.getEnumConstants()) {
columns.put(e.getIndex(), e);
}
}
public String getColumnName(int index) {
return columns.get(index).getName();
}
}
public class GenericFormatter<E extends TableColumn> extends BaseFormatter {
private TableMetadata<E> m;
public GenericFormatter(TableMetadata<E> m) {
this.m = m;
}
public String getColumnName(int columnNumber) {
return m.getColumnName(index);
}
//...
}
编辑:将 Enum
添加到type参数以获得更多的编译时安全性
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.