Я занимаюсь рефакторингом части нашего унаследованного приложения, которое обрабатывает экспорт и импорт таблиц БД из / в листы 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
и значения enum 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;
}
//...
}
Обратите внимание, что этот код является чисто экспериментальным, еще не проверенным ...
Есть ли более приятный, чистый, безопасный способ?