如何降低方法的认知复杂度

How to reduce cognitive complexity of a method

我想降低以下方法的认知复杂度。怎么做 ?以我的观点,我不能,但我对这件事没有经验

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (!(obj instanceof Bean)) return false;
   Bean other = (Bean) obj;
    if (property1== null) {
        if (other.property1!= null) return false;
    } else if (!property1.equals(other.property1)) return false;
    if (property2== null) {
        if (other.property2!= null) return false;
    } else if (!property2.equals(other.property2)) return false;
    if (property3== null) {
        if (other.property3!= null) return false;
    } else if (!property3.equals(other.property3)) return false;
    if (property4== null) {
        if (other.property4!= null) return false;
    } else if (!property4.equals(other.property4)) return false;
    return true;
}

您可以使用 Java 的 Objects.equals 轻松检查字段是否相等。如果给定的两个对象相等或都是 null,它将 return true,否则 false.

if (this == obj) return true;
if (obj == null || this.getClass() != obj.getClass()) return false;
Bean other = (Bean) obj;
return Objects.equals(this.property1, other.property1)
  && Objects.equals(this.property2, other.property2)
  && ...;

作为替代方案,Apache Commons EqualsBuilder 也提供了一个 reflectionEquals 方法,可以自动从您的 class 获取所有字段并进行比较。虽然这种方法可能会因为反射而变慢,并且您对正在发生的事情的控制较少。

我假设 Bean 是您自己的 class。您可以将 property1property2 等放入一个数组中。然后你的 equals 变成:

    public boolean equals( Object obj )
    {
        if (this == obj)
            return true;

        if (obj == null)
            return false;

        if (!(obj instanceof Bean))
            return false;

        Bean other = (Bean) obj;

        for (int i = 0; i < properties.length; i++)
            if (properties[i] == null)
            {
                if (other.properties[i] != null)
                    return false;
            }
            else if (!properties[i].equals( other.properties[i] ))
                return false;

        return true;
    }

这还使您可以在以后灵活地添加更多 属性 值,而无需修改 equals() 方法。

实用程序 class 的方法 equal 可以实现接受 Bean 属性的 getter 作为可变参数:

public class Are {
    static <T,R> boolean equal(T x1, T x2, Function<T, R> ... getters) {
        return x1 == x2 || Arrays.stream(getters)
                     .allMatch(get -> Objects.equals(get.apply(x1), get.apply(x2)));
    }
}

那么Bean::equals可以这样写:

// class Bean
@Override
public boolean equals(Object obj) {
    if (obj == null || this.getClass() != obj.getClass()) {
        return false;
    }

    Bean that = (Bean) obj;
    return Are.equal(this, that, 
        Bean::getProperty1, Bean::getProperty2, Bean::getProperty3, Bean::getProperty4
    );
}