降低圈复杂度,多个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,您应该考虑使用注释来指示应更新哪些属性。
我有以下代码:
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,您应该考虑使用注释来指示应更新哪些属性。