降低代码的复杂性

时间:2013-06-21 09:17:46

标签: java refactoring anti-patterns

我现在陷入了一些非常奇怪的类,它们的逻辑混乱了。以下是为数据库生成查询的代码示例:

if(realTraffic.getPvkp() != null) {
   //Admission point
   if(BeanUtils.isGuidEntity(realTraffic.getPvkp())) {
      findParameters +=
         " and (" + staticTableName() + ".guidPvkp = '" + realTraffic.getPvkp().getGuid()
         + "' or (" + staticTableName() + ".guidPvkpOut = '" + realTraffic.getPvkp().getGuid()
         + "' and " + staticTableName() + ".requestType = " + RequestBean.TRANSIT_TYPE
         + ")";
      if (companyType == CompanyBean.PP_TYPE && !realTraffic.isSkipOther()) {
         // TODO - add non-formed
         findParameters += " or (" + staticTableName() + ".guidPvkpOut is null "
         + " and " + staticTableName() + ".requestType = " + RequestBean.TRANSIT_TYPE
         + ")";
      }
      findParameters += ") ";
   } else {
     // Territorial department
      if(BeanUtils.isGuidEntity(realTraffic.getPvkp().getTerritorialDepartment())) {
         findParameters +=
            " and (Pvkp.guidTerritorialDepartment = '" + realTraffic.getPvkp().getTerritorialDepartment().getGuid()
            + "' or Pvkp.guidFtsDepartment = '" + realTraffic.getPvkp().getTerritorialDepartment().getGuid()
            + "' ) ";
      }
   }
}

这只是我在方法中进行的大量复杂检查的一部分。问题是 - 如何处理这样的代码 - 它有很多嵌套的if和check。为了使这段代码更简单,更优雅,常见的方法是什么?

UPD:我在编写新项目时了解如何避免此类代码,但是如何处理现有的遗留代码?

4 个答案:

答案 0 :(得分:7)

处理此类事情的好指南在鲍勃叔叔的书中,称为“清洁代码”。 在你的情况下,我会说:

  • 将字符串连接放入方法(并使用StringBuilder
  • else { if (condition) }转换为else if (condition)
  • 考虑将companyType == CompanyBean.PP_TYPE && !realTraffic.isSkipOther()放在一个单独的方法中,因为它似乎是某种业务逻辑,如果被放入一个名为if (isCompanySkippedOver(companyType, realTraffic)
  • 考虑将if(realTraffic.getPvkp() != null)反转为

    if(realTraffic.getPvkp() == null) {return;}
    

减少块缩进。

答案 1 :(得分:2)

我不希望看到用于动态生成SQL查询的所有字符串连接。你可能有一个可数集,即使它很大。我将它们作为静态最终字符串并使用PreparedStatement和绑定变量。你的方式太容易出错,可能会导致SQL注入风险。

我将该代码保存在基于接口的持久性/存储库/ DAO类中。我想考虑将其变为多态,以便我可以根据传递的参数选择版本。

它真的很复杂,想想状态机或决策树或决策表。这些可以成为驯服复杂性的好方法。

可以说OOP是要摆脱像这样的复杂逻辑。看看你是否可以使用多态和封装来消除它。

答案 2 :(得分:0)

看起来我每天必须处理的代码......

如果我碰到了很多这样的话,我会判断我是否认为未来的情况会发生变化以及我需要多少来提高代码的清晰度。

如果if的主体会改变,但条件不会,我会尝试将条件分解为返回布尔值的方法。然后,该方法将单元测试到其生命的一英寸范围内。我意识到这不是一个理想的重构,但它是一个实用的解决方案,可以提高该部分的代码清晰度。值得指出的是,我在这里谈到的代码目前没有任何单元测试,因此难以进行大规模的重构 - 我猜你处于类似的位置。

答案 3 :(得分:0)

首先编写特征测试,即将修复系统当前行为的单元测试。您至少需要进行4次测试才能涵盖所有可能的路径。

只有这样,当你受到测试的保护时,你才能重构。

如何重构取决于您的技术技能和倾向。作为一个OOP人,我可能会推动一个封装where条件的增量构建的对象:

condition.add("foo = ?", x);
condition.add("bar <> ?", y);
... 
condition.toSql(); // returns the sql code
condition.getObjects(); // returns a list of x, y...

其他方法也可行。

关键的想法是分离抽象层次;在一个级别,您有从数据库中选择内容的业务规则;在更具体的层面上,你有字符串连接。你不想混合这些水平。