Java 减少圈复杂度,多个if语句

Java 减少圈复杂度,多个if语句,java,complexity-theory,reduce,Java,Complexity Theory,Reduce,如果我没有包括这些条件,我还有很多其他条件。我如何重构它以降低圈复杂度 if (ONE.equalsIgnoreCase(eachTag.getNodeName())) { myclassDto.setOne(formatter .getElementValueAfterNullCheckWithTrim((Element) eachTag)); } else if (TWO.equalsIgnoreCase(eachTag.getNodeName())) {

如果我没有包括这些条件,我还有很多其他条件。我如何重构它以降低圈复杂度

if (ONE.equalsIgnoreCase(eachTag.getNodeName()))
{
    myclassDto.setOne(formatter
            .getElementValueAfterNullCheckWithTrim((Element) eachTag));
}
else if (TWO.equalsIgnoreCase(eachTag.getNodeName()))
{
    myclassDto.setTwo(formatter
            .getElementValueAfterNullCheckWithTrim((Element) eachTag));
}
else if (THREE.equalsIgnoreCase(eachTag.getNodeName()))
{
    myclassDto.setThree(formatter
            .getElementValueAfterNullCheckWithTrim((Element) eachTag));
}
else if (FOUR.equalsIgnoreCase(eachTag.getNodeName()))
{
    myclassDto.setFour(formatter
            .getElementValueAfterNullCheckWithTrim((Element) eachTag));
}
else if (FIVE.equalsIgnoreCase(eachTag.getNodeName()))
{
    myclassDto.setFive(formatter
            .getElementValueAfterNullCheckWithTrim((Element) eachTag));
}
else if (SIX.equalsIgnoreCase(eachTag.getNodeName()))
{
    myclassDto.setSix(formatter
            .getElementValueAfterNullCheckWithTrim((Element) eachTag));
}

如何在java中降低此函数的圈复杂度?

如果您:

  • 使用switch语句
  • 预先提取getNodeName()的值
  • 预先提取getElementValueAfterNullCheckWithTrim()返回的值

    String value = formatter.getElementValueAfterNullCheckWithTrim((Element) eachTag);
    String nodeName = eachTag.getNodeName();
    
    switch (nodeName) {
        case ONE:
            myclassDto.setOne(value);
            break;
        case TWO:
            myclassDto.setTwo(value);
            break;
        ...
    }
    
编辑: 您可能希望重构DTO,使其更易于使用,如

  myclassDto.setValue(nodeName, value)

我将定义字符串到它们对应的函数的映射。这可能是静态的

然后,您可以循环映射,找到合适的映射(
filter
)并应用该函数

private static final Map<String, BiConsumer<MyClassDto, Element>> MAPPING = new HashMap();

static
{
    mapping.put(ONE, MyClassDto::setOne);
    mapping.put(TWO, MyClassDto::setTwo);
    //...
    mapping.put(SIX, MyClassDto::setSix);
}


//...

MAPPING.entrySet().stream()
    .filter(pair -> pair.getKey().equalsIgnoreCase(eachTag.getNodeName()))
    .map(Map.Entry::getValue)
    .forEach(func -> func.accept(
        myClassDto,
        formatter.getElementValueAfterNullCheckWithTrim((Element) eachTag)
    ));
private静态最终映射=newhashmap();
静止的
{
mapping.put(一个,MyClassDto::setOne);
put(两个,MyClassDto::setTwo);
//...
mapping.put(六个,MyClassDto::setSix);
}
//...
MAPPING.entrySet().stream()
.filter(pair->pair.getKey().equalsIgnoreCase(eachTag.getNodeName())
.map(map.Entry::getValue)
.forEach(函数->函数接受)(
myClassDto,
formatter.getElementValueAfterNullCheckWithTrim((元素)eachTag)
));

您可能想考虑<代码>映射可以包含不同的密钥,这些代码被代码> >均衡器> /代码>(例如“AAA”和“AAA”)同等对待。


一种解决方案是使用
findFirst().ifPresent()
代替
forEach
(如所建议),但这可能会掩盖一些错误情况,因此请谨慎使用。

考虑到DTO的实际架构,重构部分非常重要。当我使用switch时,将复杂性从19降低到17。但是需要减少到10。正如我在回答中所说,使用
开关
与使用
if
一样“复杂”。它只是更具可读性。那么重构DTO呢?如果您的DTO在接受数据方面效率不高,即它有100套***()方法,我怀疑您会得到一个较低的复杂度数字。这可能是我的方法,但您不能以相同的结果执行
forEach
;可能会触发多个映射,并调用多个
BiConsumer
。因此,
findFirst().ifPresent()
。另外,
getNodeName
可能在流之外。@daniu我的问题是,
findFirst
可能会掩盖一些难以发现的bug。如果有两个具有不同大小写字符串的映射(例如,“AAA”和“AAA”),并且假定
HashMap
没有可预测的迭代顺序,则使用
findFirst
可能会导致在每个函数之间来回交换。这将是难以置信的难以追踪。如果你想确保没有两个“相等”的映射,最好编写一个函数来迭代键并检查重复项。同意,但如果你在代码中添加“aaa”和“aaa”,你将调用这两个
BiConsumer
s。如果他们将匹配项添加到具有唯一性约束的数据库中,则将失败。我宁愿使用
findFirst
LinkedHashMap
进行
映射(我认为这提供了确定性迭代)。对于OP的简单案例来说,这些都无关紧要;)@大牛,没错。在这种情况下,我的示例将快速失败,而您的示例将是故障安全的。我会马上知道出了什么事,而你也会幸灾乐祸地不知道