在正常的业务维护中,最怕维护别人写的代码,尤其是没有任何注释的代码。而项目文档在项目搭建的时候不重要,但后面如果有人接手,既没有项目文档,注释也懒得写,那么一些较为复杂的业务逻辑会成为噩梦。

半天梳理业务逻辑,尤其对着仅有的注释部分去尝试推测、理解代码逻辑。这里就涉及到与和或的逻辑预算,逻辑或和逻辑与运算都不是简单的多条件交集、并集。逻辑或在一个或者多个条件中有一个为 true,结果就是 true;在所有条件都为 false 的时候,结果才是 false。逻辑与相反,只要一个为 false,结果就是 false;需要所有条件都为 true,结果才是 true。

并且或和与运算存在短路原则,当或运算的前面条件返回了 true,后面的条件都不会执行了。同样的当与运算的前面条件返回了 false,后面的条件也不会执行。

逻辑与运算实例

统计已分案案件,且账龄未发生变化,且分案类型不是 a,b,c,d,e

for (CaseInfo caseInfo:list){
    CaseInfoUser oldCaseInfoUser = caseInfoUserService.selectCaseInfoUserByCaseId(caseInfo.getId());
    if(oldCaseInfoUser != null 
        && caseInfo.getAging().equals(oldCaseInfoUser.getAging())
        &&!"a".equals(oldCaseInfoUser.getCaseRuleCode())
        &&!"b".equals(oldCaseInfoUser.getCaseRuleCode())
        &&!"c".equals(oldCaseInfoUser.getCaseRuleCode())
        &&!"d".equals(oldCaseInfoUser.getCaseRuleCode())
    ) {
        num++;
        continue;
    }
    ....
}

原来的代码里有 9 个这样相同逻辑的与,然后在想自己接触到的代码写法,好像可以优化。都是不等于,可以把所有的值放到一个 List 中,通过 contains 方法来判断分案类型是否在列表中。

优化后的代码:

List<String> ruleCodes = Arrays.asList("a","b","c","d"...);
for (CaseInfo caseInfo:list){
    CaseInfoUser oldCaseInfoUser = caseInfoUserService.selectCaseInfoUserByCaseId(caseInfo.getId());
    if(oldCaseInfoUser != null 
        && caseInfo.getAging().equals(oldCaseInfoUser.getAging())
        && !ruleCodes.contains(oldCaseInfoUser.getCaseRuleCode())
    ) {
        num++;
        continue;
    }

    ...

}

突然发现 continue;,这个 continue; 不是针对 if,而是 for 循环的。所以 if 语句的逻辑就变成了 统计已分案案件,且账龄未发生变化,且分案类型不是 a,b,c,d,e,不重新分案

逻辑或运算实例

在匹配到分案规则,且分案规则不为空的前提下,需要强调只有案件从未分案,或者分案规则、规则对应的分案组别、组别下的组员发生变化,才会重新分案。

之所以没有跟前面的 if 逻辑与部分合并,主要是因为需要根据匹配到的分案规则做逻辑。

之前的逻辑:

//1.1 查看案件之前是不是已经分过规则,看下账龄有没有变化。有变化在处理
//24.4.11 若分案规则 - 分案组别、组员发生变化,重新分案
for (CaseInfo caseInfo:list) {
    
    ...

    CaseCollectionGroupUser oldGroupUser = null; // 之前的分案用户
    List<CaseCollectionGroupUser> newGroupUsers = null; // 新规则的分案用户
    if (oldCaseInfoUser != null) { // 之前的分案用户记录
        oldGroupUser = caseCollectionGroupUserService.selectCaseCollectionGroupUserById(oldCaseInfoUser.getCaseGroupUserId());
        // newGroupUsers = caseCollectionGroupUserService.selectCaseCollectionGroupUserByGroupId(caseRule.getGroupId());
    }
    if (caseInfo.getCaseRuleId() == null
        || !caseRule.getId().equals(caseInfo.getCaseRuleId()
        || !Objects.equals(oldGroupUser.getGroupId(), caseRule.getGroupId())))
            || oldGroupUser == null
        // || !newGroupUsers.stream().map(CaseCollectionGroupUser::getUserId).collect(Collectors.toList()).contains(oldGroupUser.getUserId())))
    ) {

    ...

    }

...

}

注释 1.1 的需求,通过 if + continue 已经实现了。

注释 24.4.11 若分案规则 - 分案组别、组员发生变化,重新分案,逻辑是递进的:

  • 案件从未分案
  • 案件已分案,匹配的分案规则发生变化
  • 案件已分案,匹配的分案规则未变,分案组别、组员发生变化

分案规则判断比较简单,直接比较规则编码是否一致就可以。分案组别、组员发生变化,需求主要是针对负责人员发生变动,进而调整之后,需要系统自动将案件分配给组别内的其他人。或者分案规则修改过绑定的分案组别,此时也需要重新分案。

因为分案用户记录中添加的是分案组别用户关系 ID,没有分案组别 ID 的冗余,而逻辑判断需要分案组别,所以多了一步,根据分案组别用户关系 ID 查询实际的组别组员关系表记录。

所以一开始的做的逻辑是先判断分案组别是否有变化,之后再判断组员是否还在分案组中。

  • 案件已分案,匹配的分案规则未变,分案组别发生变化
  • 案件已分案,匹配的分案规则未变,分案组别未变,组员发生变化

判断组员是否还在分案组中,需要多一次查询组别中的组员,想着是否可以优化。在看到前面增加了之前的分案用户的查询之后,想到可以根据分案用户是否存在,直接判断组员是否发生变化。因为分案用户如果发生变化,比如直接从组中去除,或者调动到其他组,都会删除组员记录,且是物理删。

新增逻辑:

//24.4.14 M3 以上案件家访默认跟2个月,若标记延长,则跟3个月
List<String> m3p = Arrays.asList("M3","M4","M5"...);

CaseCollectionGroupUser oldGroupUser = null; // 之前的分案用户
List<CaseCollectionGroupUser> newGroupUsers = null; // 新规则的分案用户
if (oldCaseInfoUser != null) { // 之前的分案用户记录
    oldGroupUser = caseCollectionGroupUserService.selectCaseCollectionGroupUserById(oldCaseInfoUser.getCaseGroupUserId());
if (caseInfo.getCaseRuleId() == null
    || (!caseRule.getId().equals(caseInfo.getCaseRuleId())
        && m3p.contains(caseInfo.getAging())
        && oldCaseInfoUser != null
        && ((Objects.equals(oldCaseInfoUser.getMyDelay(), "1")
            && DateUtils.getDaysDifference(new Date(), oldCaseInfoUser.getDivisionDate()) > 90)
            || DateUtils.getDaysDifference(new Date(), oldCaseInfoUser.getDivisionDate()) > 60))
    || (caseRule.getId().equals(caseInfo.getCaseRuleId())
        && (oldGroupUser == null
            || !Objects.equals(oldGroupUser.getGroupId(), caseRule.getGroupId())))
) {

...

}

思考了一下,这个需求还有一个隐藏的前置条件,就是已分案,且分案规则或者组别、组员得发生变化,不然按照现有条件就不会重新分案,那么自然就不需要做这个逻辑了。问了提需求的业务,分案规则或者组别、组员得发生变化条件是优先于家访 2-3 月内不重新分案的,举个例子,如果在家访 2-3 个月内出现分案规则或者组别、组员得发生变化的情况,是需要优先按照后者满足条件,进行重新分案的。

罗列现有规则条件:

  • 案件已分案,匹配的分案规则、分案组别、组员发生变化,家访 2-3 个月以内,不重新分案
  • 案件从未分案
  • 案件已分案,匹配的分案规则发生变化
  • 案件已分案,匹配的分案规则未变,分案组别发生变化
  • 案件已分案,匹配的分案规则未变,分案组别未变,组员发生变化

但第一条明显和后面的三条逻辑冲突了,且不满足分案规则或者组别、组员得发生变化的条件优先。

如果不考虑优先条件,按照逻辑或运算实例,将所有家访 2-3 个月以内的案件都排除掉,是可以实现的。但这样做,又会破坏原来想要的,只要分案规则或者组别、组员得发生变化,就重新分案的大前提。

所以,如果按照现有的条件去做,那么这个需求根本就不需要做,因为只要匹配的分案规则、分案组别、组员未变,就不会重新分案,家访 2-3 个月以内压根不需要考虑。