3

我现在被一些非常奇怪的课程所困扰,这些课程的逻辑混淆了。以下是生成数据库查询的代码示例:

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 和检查。为了使这段代码更简单、更优雅,有哪些常用方法?

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

4

4 回答 4

8

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

  • 将字符串连接放入方法中(并使用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;}
    

以减少块缩进。

于 2013-06-21T09:23:39.540 回答
2

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

我会将该代码保存在基于接口的持久性/存储库/DAO 类中。我会考虑让它成为多态的,这样我就可以根据传递的参数挑选出版本。

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

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

于 2013-06-21T09:25:29.787 回答
0

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

如果我遇到一大堆这样的 if,我会判断我是否认为未来条件会发生变化,以及我需要多少来提高代码的清晰度。

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

于 2013-06-21T09:25:37.237 回答
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...

其他方法可能有效。

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

于 2014-06-25T08:12:09.080 回答