Refactoring a Settlement Calculation Method: Identifying Code Smells and Applying Improvements

This article examines a Java settlement calculation method, identifies duplicated code and divergent change code smells, and demonstrates a refactoring using maps and enum‑based calculators to improve readability, maintainability, and adhere to object‑oriented principles.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Refactoring a Settlement Calculation Method: Identifying Code Smells and Applying Improvements

The original

private OrderShoudSettlementAmount getOrderShoudSettlementAmount(OrderDTO orderMain, List<SettlementDetail> details)

method assembles an OrderShoudSettlementAmount object by manually accumulating fee amounts for each expense type. It calculates two values: settlementMoney (the net amount) and goodCommissionMoney (the commission).

When a new fee type was added, the method was extended with additional variables ( feeMoney34012, feeMoney34013) and extra if branches, making the code longer and harder to maintain.

Applying Martin Fowler's catalog of code smells, two major issues were identified:

Duplicated Code : The for loop contains repetitive if blocks for each fee type, requiring manual updates whenever a new fee is introduced.

Divergent Change : Multiple unrelated modifications are needed in the same method whenever business rules change, violating the principle of localized change.

Beyond these smells, the method mixes object assembly with business calculations, violating object‑oriented design principles.

To address the problems, the method was refactored. The new implementation first aggregates fee amounts into a Map<Integer, Long> expenseTypeToFeeMoneyMap. Then two dedicated enum‑based calculators compute the settlement and commission values:

private OrderShoudSettlementAmount getOrderShoudSettlementAmount(OrderDTO orderMain, List<SettlementDetail> details) {
    OrderShoudSettlementAmount settlementAmount = new OrderShoudSettlementAmount();
    Map<Integer, Long> expenseTypeToFeeMoneyMap = Maps.newHashMap();
    for (SettlementDetail settlementDetail : details) {
        long feeMoney = Optional.ofNullable(expenseTypeToFeeMoneyMap.get(settlementDetail.getExpenseType())).orElse(0L);
        feeMoney += Optional.ofNullable(settlementDetail.getOassMoney()).orElse(0L);
        expenseTypeToFeeMoneyMap.put(settlementDetail.getExpenseType(), feeMoney);
    }
    long settlementMoney = SettlementMoneyCalcFeeInfoEnum.calcSettlementMoney(expenseTypeToFeeMoneyMap);
    long goodCommissionMoney = GoodCommissionMoneyCalcFeeInfoEnum.calcGoodCommissionMoney(expenseTypeToFeeMoneyMap);
    settlementAmount.setSettlementAmount(settlementMoney);
    settlementAmount.setGoodsCommission(goodCommissionMoney);
    settlementAmount.setOrderId(orderMain.getOrderId());
    settlementAmount.setOrgCode(orderMain.getOrgCode());
    settlementAmount.setStationNo(String.valueOf(orderMain.getDeliveryStationNo()));
    settlementAmount.setBillTime(new Date());
    settlementAmount.setRetSuccess(false);
    return settlementAmount;
}

The supporting enums encapsulate the calculation rules, eliminating duplicated if statements and centralizing the logic for easy updates:

enum SettlementMoneyCalcFeeInfoEnum {
    /** calculation items */
    FEE_33021(FeeInfoEnum.FEE_INFO_FREIGHT_ZS_NOSETTLE, "+"),
    FEE_33002(FeeInfoEnum.FEE_INFO_FREIGHT_YJ_ZS_NOSETTLE, "-"),
    FEE_32003(FeeInfoEnum.FEE_INFO_GOODS_YJ_WJTZ, "-"),
    FEE_32001(FeeInfoEnum.FEE_INFO_GOODS_NOSETTLE, "+"),
    FEE_31001(FeeInfoEnum.FEE_INFO_BDYJ_YJ_NOSETTLE, "-"),
    FEE_34012(FeeInfoEnum.FEE_INFO_CHF_XSG_NOSETTLE, "+"),
    FEE_34013(FeeInfoEnum.FEE_INFO_CHF_YJ_XSG, "-");
    private final FeeInfoEnum feeInfoEnum;
    private final String symbol;
    SettlementMoneyCalcFeeInfoEnum(FeeInfoEnum feeInfoEnum, String symbol) {
        this.feeInfoEnum = feeInfoEnum;
        this.symbol = symbol;
    }
    public static long calcSettlementMoney(Map<Integer, Long> expenseTypeToFeeMoneyMap) {
        long settlementMoney = 0L;
        for (SettlementMoneyCalcFeeInfoEnum calcFeeInfoEnum : SettlementMoneyCalcFeeInfoEnum.values()) {
            if ("+".equals(calcFeeInfoEnum.symbol)) {
                settlementMoney += Optional.ofNullable(expenseTypeToFeeMoneyMap.get(calcFeeInfoEnum.feeInfoEnum.getVal())).orElse(0L);
            }
            if ("-".equals(calcFeeInfoEnum.symbol)) {
                settlementMoney -= Optional.ofNullable(expenseTypeToFeeMoneyMap.get(calcFeeInfoEnum.feeInfoEnum.getVal())).orElse(0L);
            }
        }
        return settlementMoney;
    }
}
enum GoodCommissionMoneyCalcFeeInfoEnum {
    /** calculation items */
    FEE_33005(FeeInfoEnum.FEE_INFO_YFYJ_ZS_XSG),
    FEE_33002(FeeInfoEnum.FEE_INFO_FREIGHT_YJ_ZS_NOSETTLE),
    FEE_32003(FeeInfoEnum.FEE_INFO_GOODS_YJ_WJTZ),
    FEE_31001(FeeInfoEnum.FEE_INFO_BDYJ_YJ_NOSETTLE),
    FEE_34013(FeeInfoEnum.FEE_INFO_CHF_YJ_XSG);
    private final FeeInfoEnum feeInfoEnum;
    GoodCommissionMoneyCalcFeeInfoEnum(FeeInfoEnum feeInfoEnum) {
        this.feeInfoEnum = feeInfoEnum;
    }
    public static long calcGoodCommissionMoney(Map<Integer, Long> expenseTypeToFeeMoneyMap) {
        long goodCommissionMoney = 0L;
        for (GoodCommissionMoneyCalcFeeInfoEnum calcFeeInfoEnum : GoodCommissionMoneyCalcFeeInfoEnum.values()) {
            goodCommissionMoney += Optional.ofNullable(expenseTypeToFeeMoneyMap.get(calcFeeInfoEnum.feeInfoEnum.getVal())).orElse(0L);
        }
        return goodCommissionMoney;
    }
}

The refactoring removes duplicated conditional logic, centralizes calculation rules, and separates data aggregation from business computation, thereby reducing divergent change and improving maintainability. The article concludes by reminding readers of the "broken‑window" effect in software engineering: neglecting small quality issues can lead to larger, harder‑to‑fix problems, so regular refactoring is essential for long‑term code health.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavarefactoringDesign Principlescode smells
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.