前言
有位同事踩了一个代码低内聚的坑。我给大家分享一下,避坑。
1. 问题背景与代码示例
假设我们有一个 RepayPlan 类,最初的版本代码如下:
public class RepayPlan {
private long principal; // 本金
private long interest; // 利息
private long fee; // 费用
private long totalAmt; // 总金额
private long repaidPrincipal; // 已还本金
private long repaidInterest; // 已还利息
private long repaidFee; // 已还费用
private long totalRepaidAmt; // 总的已还金额
// getters and setters omitted for brevity
}
在某次需求变更中,我们新增了一个 reducePrincipal 字段,用来表示减免的本金:
public class RepayPlan {
private long principal; // 本金
private long interest; // 利息
private long fee; // 费用
private long totalAmt; // 总金额
private long repaidPrincipal; // 已还本金
private long repaidInterest; // 已还利息
private long repaidFee; // 已还费用
private long totalRepaidAmt; // 总的已还金额
private long reducePrincipal; // 减免本金 (新增字段)
}
我们有多个接口,比如查询还款计划、还款试算、查询剩余未还金额,都需计算剩余未还本金。于是我们新增了减免本金字段,各个接口都需要改。
查询还款计划接口:
public long calculateRemainingPrincipal(RepayPlan plan) {
return plan.getPrincipal() - plan.getRepaidPrincipal();
}
还款试算接口:
public long calculateRemainingPrincipalForSimulation(RepayPlan plan) {
return plan.getPrincipal() - plan.getRepaidPrincipal();
}
查询剩余未还本金接口:
public long queryRemainingPrincipal(RepayPlan plan) {
return plan.getPrincipal() - plan.getRepaidPrincipal();
}
需求变更后,计算剩余未还本金的逻辑变更为:
剩余未还本金 = 本金 - 已还本金 - 减免本金
于是,上面提到的三个接口,都需要修改。。。然后我同事修改漏了一个,喜提一个bug
2.解决方案
以上的这个场景,就是算代码低内聚的坑啦。假设你有十几个接口,每个接口的计算逻辑本来是通用的,各个接口确实各写个的,当新增一个字段或者修改某个字段时,就很容易出现改漏的情况。
为了解决这个问题,我们可以创建一个工具类 RepaymentCalculator,将所有的计算逻辑封装在其中,以确保逻辑的统一和维护的便捷性。如果下次再有类似的变更的时候,只需要修改工具类一个地方即可.
public class RepaymentCalculator {
// 计算剩余未还本金
public static long calculateRemainingPrincipal(RepayPlan plan) {
return plan.getPrincipal() - plan.getRepaidPrincipal() - plan.getReducePrincipal();
}
查询还款计划接口:
public long calculateRemainingPrincipal(RepayPlan plan) {
return RepaymentCalculator.calculateRemainingPrincipal(plan);
}
还款试算接口:
public long calculateRemainingPrincipalForSimulation(RepayPlan plan) {
return RepaymentCalculator.calculateRemainingPrincipal(plan);
}
查询剩余未还本金接口:
public long queryRemainingPrincipal(RepayPlan plan) {
return RepaymentCalculator.calculateRemainingPrincipal(plan);
}
最后
在实际项目中,我们应当时刻保持对代码复用性和内聚性的关注,尤其是在面对频繁变更的业务需求时,封装公用逻辑是一种非常有效的策略。这样即使需求变更,有十几个接口要改,我们也是修改工具类里面一个地方即可。