1. Long Method(过长函数)的危害与 Extract Method 的拆分判据中以"意图"而非"行数"切分
过长函数(Long Method)会带来哪些危害?在应用 Extract Method 重构时,应当依据什么标准来切分函数,是以代码行数还是以"意图"为依据?
- 过长函数对可读性、可维护性与可测试性的具体危害
- Extract Method 的拆分判据:以语义意图为边界而非行数
- 提取后函数命名与注释的职责归属
过长函数的危害在于它把"一段连续逻辑"的多个独立意图混在一起,导致阅读者难以快速定位"某一段在做什么"、测试难以针对单一行为进行、修改时容易产生副作用并提高出错率。Extract Method 的核心判据不是行数,而是"意图"——当一段代码能用一个有意义的名字来描述它所做的事情时,就应当把它提取成独立方法,使方法名成为这段代码的注释,从而让上层函数只描述"做什么"而非"怎么做"。行数只是参考信号,真正的标准是"该方法是否只做一件事、是否能在同一抽象层级上被描述"。
依赖行数切分会导致机械切分,把本属同一意图的代码生硬拆开,反而增加跳转成本;而以意图切分则让每个方法都有一个清晰的职责与命名,符合单一职责原则在函数层面的体现。实践中常以"注释的存在"作为信号:如果一个方法里需要注释来解释某段代码,就该考虑提取。提取后方法名应能替代原注释,这既是重构也是可读性的提升。
// 重构前:一个方法承担多个意图
public void processOrder(Order order) {
double total = 0;
for (LineItem item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
}
if (total > 1000) {
Customer c = order.getCustomer();
if (c.getLevel().equals("VIP")) {
c.setDiscount(0.9);
}
}
this.sendInvoice(order, total);
}
// 重构后:按意图拆分
public void processOrder(Order order) {
double total = computeTotal(order);
applyVipDiscount(order, total);
this.sendInvoice(order, total);
}
private double computeTotal(Order order) { /* 计算总价 */ }
private void applyVipDiscount(Order order, double total) { /* 折扣逻辑 */ }