Проблема с enum в том, что вы не можете использовать универсальные типы.Вы можете увидеть больше об этом в Как реализовать enum с помощью дженериков? .
Во-первых, нам нужно создать «enum-like» класс с константами, используя универсальные типы.
class Column<T> {
public static final Column<String> TEXT_VALUE = new Column<>("Text_Column_Name", String.class);
public static final Column<Number> NUMERIC_VALUE = new Column<>("Numeric_Column_Name", Number.class);
public static final Column<Date> DATE_VALUE = new Column<>("Date_Column_Name", Date.class);
String name;
Class<T> clazz;
private Column(String name, Class<T> clazz){
this.name = name;
this.clazz = clazz;
}
}
Таким образом, мы можем обеспечить вставку значения в карту для соответствия типу Column
с помощью метода:
public <U> void setValue(Column<U> column, DocumentCell<U> value) {
rowContents.put(column, value);
}
Пример:
DocumentRow row = new DocumentRow();
row.setValue(Column.TEXT_VALUE, new DocumentCell<String>("asdf"));
row.setValue(Column.TEXT_VALUE, new DocumentCell<Integer>(4)); //Don't compile, can't set an `Integer` document cell into a `Column.TEXT_VALUE`
Теперь мы уверены, что значение, вставленное для Column.TEXT_VALUE
, будет содержать String
, и то же самое для всех Column
констант.
Поскольку мы застраховали тип во время вставки, мы можем испачкатьсяи приведите DocumentCell<?>
с карты к тому же типу Column
:
public <U> U getValue(Column<U> column) {
@SuppressWarnings("unchecked")
DocumentCell<U> doc = (DocumentCell<U>) rowContents.get(column);
return doc.getValue(column);
}
и небольшой пример результата:
String s = row.getValue(Column.TEXT_VALUE);
Integer i = row.getValue(Column.TEXT_VALUE); //DON'T COMPILE : `row.getValue` will return a value of the type define by `Column`, here a `String`
Полный пример использования:
DocumentRow row = new DocumentRow();
row.setValue(Column.TEXT_VALUE, new DocumentCell<>("asdf"));
row.setValue(Column.NUMERIC_VALUE, new DocumentCell<>(4));
row.setValue(Column.DATE_VALUE, new DocumentCell<>(new Date()));
String s = row.getValue(Column.TEXT_VALUE);
Number i = row.getValue(Column.NUMERIC_VALUE);
Date d = row.getValue(Column.DATE_VALUE);
Обратите внимание, что в последнем примере я не предоставлял тип для DocumentCell
, компилятор знает, что он будет использовать тот же параметр Column
, что и раньше.
И вы можетенайти полный код этого проекта ideone .
Конечно, мы можем отбросить "enum-like" часть aи инициализировал экземпляр Column
по необходимости.Все, что нам нужно сделать, это сделать конструктор видимым (по крайней мере, не закрытым), и мы можем создать новые «сопоставления типов столбцов»
Column<LocalDateTime> colDate = new Column<>("A new Date", LocalDateTime.class);
row.setValue(colDate , new DocumentCell<>(LocalDateTime.now()));