You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《Clean Code》异常处理代码解析及特殊案例模式重构咨询

《Clean Code》错误处理:原代码解读与特殊案例模式重构

一、原代码含义

先看这段Java代码:

try {
 MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
 m_total += expenses.getTotal();
} catch(MealExpensesNotFound e) {
 m_total += getMealPerDiem();
}

这段逻辑很直白:

  • 调用expenseReportDAO.getMeals(员工ID),从报销系统里查询该员工的餐费报销明细(返回的MealExpenses对象包含餐费总金额)
  • 将查到的餐费总额加到m_total(总费用)中
  • 如果系统里找不到该员工的餐费记录,就会抛出MealExpensesNotFound异常,这时改用每日餐补标准(getMealPerDiem()的返回值)加到总费用里

本质是用异常处理应对“找不到餐费记录”的特殊场景,但《Clean Code》认为这种写法不够优雅——异常应该用来处理意外错误,而“没有餐费记录”属于业务上的常规情况,不该用异常来控制流程。

二、特殊案例模式重构思路

书中给出的PerDiemMealExpenses类是特殊案例模式的核心:

public class PerDiemMealExpenses implements MealExpenses {
 public int getTotal() {
 // return the per diem default
 }
}

重构核心逻辑:

  1. 把特殊场景包装成正常对象:
    PerDiemMealExpenses实现了和正常餐费记录一致的MealExpenses接口,它的getTotal()方法直接返回每日餐补的固定数值(比如每天60元)。这个对象就代表“无餐费记录时的默认餐费”。

  2. 修改查询工具的逻辑:
    让expenseReportDAO.getMeals()方法不再抛出MealExpensesNotFound异常——当查不到员工的餐费记录时,直接返回PerDiemMealExpenses的实例,而非抛出异常。

  3. 简化业务代码:
    原来的try-catch可以完全删掉,直接写成:

    MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
    m_total += expenses.getTotal();
    

    不管是查到真实餐费记录,还是触发“无记录”的特殊情况,代码都能统一调用getTotal(),不用再处理异常,逻辑更简洁,也贴合“面向接口编程”的思想。

重构的优势:

  • 去掉异常流程后,代码可读性大幅提升,一眼就能看懂是“拿餐费加总”,不用绕到catch块里看特殊逻辑
  • “默认餐补”的逻辑被封装到专门类中,符合单一职责原则,以后要调整餐补标准,只需要修改PerDiemMealExpenses即可
  • 避免了异常处理带来的额外性能开销(异常流程的执行成本比正常流程高)

内容的提问来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 05:26:46