【发布时间】:2021-12-27 18:00:50
【问题描述】:
在我当前的项目中,我需要在仅在运行时知道的类型之间转换值:输入类型是输入的 JSON 类型,输出类型在运行时加载的配置文件中定义。
我想出了一个通用的解决方案,但我对它不太满意,因为支持新的输入类型意味着您需要更改现有支持的输出类型类(这违反了开/关原则),我使用很多instanceof 和很多演员。
在可维护性方面,有没有比我做的更好的解决方案?
我试图获得一种我的代码的最小示例,所以这里是:
package org.example.scratch;
import static java.lang.Float.*;
import static java.lang.Integer.*;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import lombok.Value;
class Scratch {
public static void main(String[] args) {
// runtime values
final FieldValue value = StringValue.of("3.14"); // input value
final Converter<?> converter = FloatConverter.of(); // output type
Mapper<?> mapper = Mapper.of(converter);
FieldValue converted = mapper.convert(value);
System.out.println(converted);
}
@Value(staticConstructor = "of")
static class Mapper<T extends FieldValue> {
Converter<T> converter;
public T convert(FieldValue value) {
return converter.apply(value);
}
}
interface Converter<T extends FieldValue> {
T apply(FieldValue value);
}
@Value(staticConstructor = "of")
static class IntegerConverter implements Converter<IntegerValue> {
@Override
public IntegerValue apply(FieldValue value) {
if (value instanceof IntegerValue) {
return (IntegerValue) value;
}
if (value instanceof FloatValue) {
return IntegerValue.of(((FloatValue) value).getValue().intValue());
}
if (value instanceof StringValue) {
return IntegerValue.of(parseInt(((StringValue) value).getValue()));
}
throw new IllegalArgumentException("Impossible to convert a " + value.getClass().getName() + " to a " + IntegerValue.class.getSimpleName());
}
}
@Value(staticConstructor = "of")
static class FloatConverter implements Converter<FloatValue> {
@Override
public FloatValue apply(FieldValue value) {
if (value instanceof FloatValue) {
return (FloatValue) value;
}
if (value instanceof IntegerValue) {
return FloatValue.of(((IntegerValue) value).getValue().floatValue());
}
if (value instanceof StringValue) {
return FloatValue.of(parseFloat(((StringValue) value).getValue()));
}
throw new IllegalArgumentException("Impossible to convert a " + value.getClass().getName() + " to a " + FloatValue.class.getSimpleName());
}
}
@Value(staticConstructor = "of")
static class DateConverter implements Converter<DateValue> {
@Override
public DateValue apply(FieldValue value) {
if (value instanceof DateValue) {
return (DateValue) value;
}
if (value instanceof StringValue) {
return DateValue.of(LocalDate.parse(((StringValue) value).getValue()));
}
throw new IllegalArgumentException("Impossible to convert a " + value.getClass().getName() + " to a " + DateValue.class.getSimpleName());
}
}
@Value(staticConstructor = "of")
static class TimestampConverter implements Converter<TimestampValue> {
@Override
public TimestampValue apply(FieldValue value) {
if (value instanceof TimestampValue) {
return (TimestampValue) value;
}
if (value instanceof StringValue) {
return TimestampValue.of(ZonedDateTime.parse(((StringValue) value).getValue()));
}
throw new IllegalArgumentException("Impossible to convert a " + value.getClass().getName() + " to a " + TimestampValue.class.getSimpleName());
}
}
interface FieldValue {}
@Value(staticConstructor = "of")
static class IntegerValue implements FieldValue {
Integer value;
}
@Value(staticConstructor = "of")
static class FloatValue implements FieldValue {
Float value;
}
@Value(staticConstructor = "of")
static class DateValue implements FieldValue {
LocalDate value;
}
@Value(staticConstructor = "of")
static class TimestampValue implements FieldValue {
ZonedDateTime value;
}
@Value(staticConstructor = "of")
static class StringValue implements FieldValue {
String value;
}
}
【问题讨论】:
标签: java generics refactoring instanceof maintainability