Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 降低圈复杂度_Java_Cyclomatic Complexity - Fatal编程技术网

Java 降低圈复杂度

Java 降低圈复杂度,java,cyclomatic-complexity,Java,Cyclomatic Complexity,我有一个类,它包含20多个相同类型的字段,这些字段在对象生命周期的不同阶段填充 其中一个类方法应基于字段名返回字段值 到目前为止,我有这样的想法: public String getFieldValue(String fieldName){ switch (fieldName.toLowerCase(){ case "id": return getId(); case "name": return getName(); ..... public String getFieldValue(Str

我有一个类,它包含20多个相同类型的字段,这些字段在对象生命周期的不同阶段填充

其中一个类方法应基于字段名返回字段值

到目前为止,我有这样的想法:

public String getFieldValue(String fieldName){
switch (fieldName.toLowerCase(){
case "id": return getId();
case "name": return getName();
.....
public String getFieldValue(String fieldName){
    return PropertyUtils.getSimpleProperty(fieldName.toLowerCase());
}
问题是圈复杂度很高


解决这个问题最简单的方法是什么?

理论上,您可以通过以下方式降低
getFieldValue()
方法的复杂性:


  • 将getter方法引用存储为
    Producer
    中的
    Map

    编辑:感谢@Filippo Possenti的评论

    您可以使用
    映射来代替开关

    这里有一个例子

    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);
    }
    
    静态接口C{
    字符串getA();
    字符串getB();
    字符串getC();
    }
    @功能接口
    静态接口FieldGetter{
    字符串get(C);
    }
    静态映射字段=Map.of(
    “a”,C::getA,
    “b”,C::getB,
    “c”,c::getC
    );
    静态字符串getField(C对象,字符串字段名检索){
    var getter=fields.get(fieldnametoretrive);
    if(getter==null){
    抛出新的IllegalArgumentException(“未知字段”);
    }
    返回getter.get(对象);
    }
    

    为什么不为此使用反射或现有库?(或者为什么会有这种方法)

    假设
    fieldName
    可能的值与bean上的getter匹配,您可以使用Apache的BeanUtils:

    基本上,你可以这样做:

    public String getFieldValue(String fieldName){
    switch (fieldName.toLowerCase(){
    case "id": return getId();
    case "name": return getName();
    .....
    
    public String getFieldValue(String fieldName){
        return PropertyUtils.getSimpleProperty(fieldName.toLowerCase());
    }
    
    这更多的是关于提高代码可读性,而不是改进圈复杂度,所以如果您追求的是纯性能,那么这可能不是您的解决方案

    如果您追求的是纯性能,那么您可以尝试利用lambdas和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"));
        }
    }
    
    import java.util.Map;
    导入java.util.HashMap;
    导入java.util.function.function;
    公共类HelloWorld{
    公共静态类MyClass{
    私有静态映射描述符;
    静止的{
    descriptor=newhashmap();
    descriptor.put(“id”,MyClass::getId);
    descriptor.put(“name”,MyClass::getName);
    }
    私有字符串id;
    私有字符串名称;
    公共字符串getId(){
    返回id;
    }
    公共字符串getName(){
    返回名称;
    }
    公共void setId(字符串值){
    id=值;
    }
    公共void集合名(字符串值){
    名称=值;
    }
    公共对象getFieldValue(字符串fieldName){
    函数fn=descriptor.get(fieldName);
    返回fn.应用(本);
    }
    }
    公共静态void main(字符串[]args){
    MyClass mc=新的MyClass();
    mc.setId(“你好”);
    mc.setName(“世界”);
    System.out.println(mc.getFieldValue(“id”)+“”+mc.getFieldValue(“名称”);
    }
    }
    
    注意,在上面的示例中,圈复杂度仍然存在,但它在类的静态初始化器中移动了。这意味着您将在应用程序启动期间受到适度的惩罚,但在随后调用
    getFieldValue
    时,您将享受更高的性能。
    此外,如果您追求的是性能,那么您可能希望消除对小写字母的需求。。。在我的示例中,我删除了它。

    您可以使用
    枚举来代替开关或使用
    映射

    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);
        }
    }
    

    在您的客户代码中。

    您可以使用单一退货。但这一变化真的会让事情变得更清晰/可读/可维护吗?有时,这些标志可以被忽略。这是不应该做的事情。但如果你真的必须这样做,这将是反射的用例。我可以使用一个返回,但这不会影响圈复杂度分数。关于反射,如果没有其他方法,我将求助于反射,但如果有不同的路径,我宁愿尝试不同的路径。每个
    返回的不是增加圈复杂度吗?您可以将实际字段值存储在
    映射中,然后通过
    公共字符串getId()实现getter{return fields.get(“id”);}
    例如,为什么要遍历映射?他不能直接调用
    fields.get(fieldName)
    ?@FilipPossenti非常感谢。默认情况下,我倾向于使用
    Stream
    ,即使它根本不需要!您应该能够在这里编写方法引用而不是lambda:
    C::getA
    等等。