我有一个类,在对象生命周期的不同阶段填充了20多个相同类型的字段。
其中一个类方法应根据字段名称返回字段值。
到目前为止,我有这样的事情:
public String getFieldValue(String fieldName){
switch (fieldName.toLowerCase(){
case "id": return getId();
case "name": return getName();
.....
问题是圈复杂度高。
解决这个问题的最简单方法是什么?
答案 0 :(得分:1)
编辑:感谢 @Filippo Possenti 的评论
您可以使用Map
来代替开关。
这里是一个例子。
static interface C {
String getA();
String getB();
String getC();
}
@FunctionalInterface
static interface FieldGetter {
String get(C c);
}
static Map<String, FieldGetter> fields = Map.of(
"a", C::getA,
"b", C::getB,
"c", C::getC
);
static String getField(C object, String fieldNameToRetrieve) {
var getter = fields.get(fieldNameToRetrieve);
if(getter == null) {
throw new IllegalArgumentException("unknown field");
}
return getter.get(object);
}
您为什么不为此使用反射或现有库? (或者为什么你甚至有这种方法)
答案 1 :(得分:0)
理论上,您可以通过以下方式降低getFieldValue()
方法的复杂性:
Producer<?>
中将getter方法引用存储为Map<String, Producer<?>>
但是,这些方法中的每一种都会增加getFieldValue()
方法的复杂性并可能降低性能。两者都是比高复杂性更糟糕的问题。
感觉您应该首先回顾为什么需要getFieldValue()
方法,也许应该是Map<String, ?>
?
答案 2 :(得分:0)
假设fieldName
的可能值与Bean上的getter匹配,则可以使用Apache的BeanUtils:
基本上,您可以执行以下操作:
public String getFieldValue(String fieldName){
return PropertyUtils.getSimpleProperty(fieldName.toLowerCase());
}
与提高循环复杂性相比,这更多是关于提高代码的可读性,因此,如果您只是追求纯粹的性能,那么这可能不是您的解决方案。
如果您只追求纯粹的性能,则可以尝试利用lambda和Map。
import java.util.Map;
import java.util.HashMap;
import java.util.function.Function;
public class HelloWorld{
public static class MyClass {
private static Map<String, Function<MyClass, Object>> descriptor;
static {
descriptor = new HashMap<>();
descriptor.put("id", MyClass::getId);
descriptor.put("name", MyClass::getName);
}
private String id;
private String name;
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setId(String value) {
id = value;
}
public void setName(String value) {
name = value;
}
public Object getFieldValue(String fieldName) {
Function fn = descriptor.get(fieldName);
return fn.apply(this);
}
}
public static void main(String []args){
MyClass mc = new MyClass();
mc.setId("hello");
mc.setName("world");
System.out.println(mc.getFieldValue("id") + " " + mc.getFieldValue("name"));
}
}
要注意的是,在上面的示例中,圈复杂性仍然存在,但已在类的静态初始化器中移动了。这意味着您将在应用程序启动期间遭受适度的损失,但是在随后的getFieldValue
调用中将获得更高的性能。
另外,如果您想要的是性能,则可能需要消除对toLowerCase
...的需要,在我的示例中,我已将其删除。
答案 3 :(得分:0)
您可以使用Map
代替开关或使用enum
。
enum FieldExtractor implements Function<YourClass, String> {
ID(YourClass::getId),
NAME(YourClass::getName); // and so on
private final Function<YourClass, String> delegate;
FieldExtractor(Function<YourClass, String> delegate) {
this.delegate = delegate;
}
@Override public String apply(YourClass extractFrom) {
return delegate.apply(extractFrom);
}
static FieldExtractor fromString(String name) {
return Stream.of(FieldExtractor.values())
.filter(fe -> fe.name().equalsIgnoreCase(name))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
}
现在您可以使用
public String getFieldValue(String fieldName) {
return FieldExtractor.fromString(fieldName).apply(this);
}
在您的客户代码中。