过长函数为什么是问题
函数越长,越难理解、越难测试、越难复用:读的人需要在脑子里一次装下太多状态,改动时也很难判断影响范围。处理路径是提取与分解——把注释当作段落标题的代码块、条件分支、循环体都可以提炼成有名字的函数。长度只是信号,可理解性才是目标。
基本信息
| 信号 | 需要滚动多屏才能读完;注释充当段落标题 |
|---|---|
| 常用手法 | 提炼函数、分解条件表达式、用查询替代临时变量 |
| 判断标准 | 函数是否在做多件事,每件事能否被命名 |
| 收益 | 每段逻辑可单独命名、单独测试、单独复用 |
分解的思路
- 把注释当作待提炼的清单:每条解释意图的注释都是一个候选函数名。
- 先处理条件分支:把复杂的条件表达式提炼成命名清晰的判断函数。
- 循环体独立出来:循环内做多件事时,先提炼循环体再简化循环本身。
- 减少临时变量:用查询替代临时变量,能明显降低提炼难度。
- 按层次组织:外层函数描述步骤,细节下沉到被调用的小函数里。
- 注释充当分隔线时就是拆分信号:能被一条注释概括的一段,通常也可以成为一个命名函数。
分解思路示例
分解思路示例
parseOrder() {
validate(order);
price = priceOf(order);
discounts = discountFor(order);
receipt = receiptOf(order, price, discounts);
}长函数的典型成因
| 成因 | 处理方向 |
|---|---|
| 注释充当段落标题 | 把每段提炼成命名函数 |
| 条件分支嵌套过深 | 分解条件表达式,提前返回 |
| 循环内混合多种职责 | 提炼循环体,分离数据处理与输出 |
| 临时变量过多 | 用查询替代临时变量 |
| 顺序依赖的多个步骤 | 按步骤提炼成独立方法 |
判断标准不是行数阈值,而是:函数是否在做多件事、每件事是否可以被命名。
提炼后函数数量会变多:命名清晰、层次分明时,阅读成本反而下降,因为读者可以按层次选择阅读深度。
拆分前后都要跑一遍测试:长函数牵涉的状态较多,机械修改也容易顺手改错。