《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 } }
重构核心逻辑:
把特殊场景包装成正常对象:
PerDiemMealExpenses实现了和正常餐费记录一致的MealExpenses接口,它的getTotal()方法直接返回每日餐补的固定数值(比如每天60元)。这个对象就代表“无餐费记录时的默认餐费”。修改查询工具的逻辑:
让expenseReportDAO.getMeals()方法不再抛出MealExpensesNotFound异常——当查不到员工的餐费记录时,直接返回PerDiemMealExpenses的实例,而非抛出异常。简化业务代码:
原来的try-catch可以完全删掉,直接写成:MealExpenses expenses = expenseReportDAO.getMeals(employee.getID()); m_total += expenses.getTotal();不管是查到真实餐费记录,还是触发“无记录”的特殊情况,代码都能统一调用
getTotal(),不用再处理异常,逻辑更简洁,也贴合“面向接口编程”的思想。
重构的优势:
- 去掉异常流程后,代码可读性大幅提升,一眼就能看懂是“拿餐费加总”,不用绕到catch块里看特殊逻辑
- “默认餐补”的逻辑被封装到专门类中,符合单一职责原则,以后要调整餐补标准,只需要修改
PerDiemMealExpenses即可 - 避免了异常处理带来的额外性能开销(异常流程的执行成本比正常流程高)
内容的提问来源于stack exchange,提问作者anon
相关产品推荐
相关产品推荐

