降低圈复杂度,多个if语句

Reducing the cyclomatic complexity, multiple if statements

我有以下代码:

private Facility updateFacility(Facility newFacility, Facility oldFacility) {
    if (newFacility.getCity() != null)
        oldFacility.setCity(newFacility.getCity());
    if (newFacility.getContactEmail() != null) 
        oldFacility.setContactEmail(newFacility.getContactEmail());
    if (newFacility.getContactFax() != null) 
        oldFacility.setContactFax(newFacility.getContactFax());
    if (newFacility.getContactName() != null) 
        oldFacility.setContactName(newFacility.getContactName());
    // ......
}

大约有 14 个这样的检查和作业。也就是说,除了少数,我需要修改 oldFacility 对象的所有字段。我得到这个代码 14 的圈复杂度,根据 SonarQube,它是 "greater than 10 authorized"。关于如何降低圈复杂度的任何想法?

在您的程序中的某个时刻,您将必须实现以下逻辑:

  • 如果新设施定义了 属性,则相应地更新旧设施
  • 如果不是,请不要覆盖旧设施中的先前值。

无需全局查看您的项目,您可以做的是将该逻辑移动到每个 属性:

的 setter 中
public class Facility {

    public void setSomething(String something) {
        if (something != null) {
            this.something = something;
        }
    }

}

这样,您的 update 方法就是:

private Facility updateFacility(Facility newFacility, Facility oldFacility) {
    oldFacility.setSomething(newFacility.getSomething());
    // etc for the rest
}

您可以覆盖 Facility class 中的 hashCode 和 equals 方法,并执行以下操作:

if(!newFacility.equals(oldFacility))
 {
    //only when something is changed in newFacility, this condition will be excecuted
    oldFacility = newFacility;
 }
 return oldFacility;
 //This is just and example, you can return newFacility directly

注意 :您可以包含所有参数或仅包含决定唯一性的参数。由你决定。
希望这对您有所帮助!

我认为您可以应用构建器模式来解决这个问题,它可能会帮助您消除 if 语句循环中的挫败感。请参阅 this link 了解更多详情

您可以将您不想修改的 oldFacility 对象的字段复制到其他变量,然后更新整个 oldFacility 对象,并只替换您没有修改的字段' 想随存储在其他变量中的内容而变化。即

private Facility updateFacility(Facility newFacility, Facility oldFacility){
    String contentNotToBeModified; // or whatever variable type
    contentNotToBeModified = oldFacility.getCity();
    // Do the same for all data that you want to keep

    oldFacility = newFacility;
    newFacility.setCity(contentNotToBeModified);
}

所以先把你想保留在oldFacility之外的数据复制出来,然后用oldFacility代替newFacility,把newFacility需要的属性替换成来自 oldFacility 的数据。

not null 检查对我来说似乎毫无意义,因为如果你像这样稍微修改你的例子, NullPointerException 就不会被抛出:

private Facility updateFacility(Facility newFacility, Facility oldFacility) {

if (newFacility != null) {

    oldFacility.setCity(newFacility.getCity());
    oldFacility.setContactEmail(newFacility.getContactEmail());
    oldFacility.setContactFax(newFacility.getContactFax());
    oldFacility.setContactName(newFacility.getContactName());
    ...
}

这会将 null 值分配给无论如何都引用 null 的引用,并且不会导致任何问题。

假设您正在做类似 newFacility.getCity().toString() 的事情,那么检查将很有用。

您可以使用 Java 反射来避免 copy/paste/write-same-Problem:

public Facility updateFacility(Facility newFacility, Facility oldFacility)
{
    String[] properties = {"City", "ContactEmail", "ContactFax", "ContactName"};
    for(String prop : properties) {
        try {
            Method getter = Facility.class.getMethod("get"+prop);
            Method setter = Facility.class.getMethod("set"+prop, getter.getReturnType());
            Object newValue = getter.invoke(newFacility);
            if (newValue != null)
                setter.invoke(oldFacility, newValue);
        } catch (NoSuchMethodException | 
                SecurityException | 
                IllegalAccessException | 
                InvocationTargetException ex) {
             throw new RuntimeException(ex);
        }
    }
    ...
}

现在,当设施 class 中有您想要更新的新属性时,您可以简单地更改属性 [] 数组。

编辑:如果使用return类型的getter方法来查找setter方法,则不需要假设 Facility 的属性都是同一类型。

注意事项: 重命名方法时要小心!如果您从 Facility class 重命名或删除方法,此代码将导致运行时错误。如果您必须更改设施的代码 class,您应该考虑使用注释来指示应更新哪些属性。