简介
“将语句移动到调用者处”(Move Statements to Callers)是一种重构手法,通过将方法内部的某些语句移动到调用该方法的位置,来提高代码的灵活性和职责单一性。这种重构适用于方法中存在与核心逻辑耦合度较低的代码,或需要不同调用者差异化处理的场景。
针对的症状(代码坏味道)
- 方法承担了多个职责(Multifaceted Method)
- 方法内部包含调用者特有的逻辑(Caller-Specific Logic in Method)
- 代码块在不同调用场景中需要差异化执行(Divergent Behavior in Calls)
将语句移动到调用者处(Move Statements to Callers)的详细步骤
- 识别需要移动的代码块
- 寻找方法中与核心逻辑关联度低的代码
- 识别调用者可能需要定制/控制的逻辑片段
- 评估代码移动后的影响范围
- 调整原始方法
- 将目标代码块从原方法中移除
- 添加必要的返回值或参数
- 确保原方法保持功能完整性
- 修改调用点
- 在调用位置添加被移出的代码
- 处理返回值或参数传递
- 保持原有业务逻辑不变
- 测试验证
- 运行单元测试验证功能正确性
- 特别注意多个调用点的差异性
- 代码审查
- 检查是否引入重复代码
- 验证职责划分合理性
示例
原始代码:
class OrderProcessor {
public void processOrder(Order order) {
double total = calculateTotal(order);
// 需要移动的日志语句
System.out.println("Order processed: " + order.getId());
applyTax(total);
}
private double calculateTotal(Order order) { }
private void applyTax(double amount) { }
}
重构步骤:
- 识别需要移动的日志语句
- 从 processOrder 方法中移除日志代码
- 在每个调用点添加日志语句
重构后:
class OrderProcessor {
// 修改后的方法
public void processOrder(Order order) {
double total = calculateTotal(order);
applyTax(total);
}
// 新增公共方法供调用者获取计算结果
public double getCalculatedTotal(Order order) {
return calculateTotal(order);
}
// 其他方法保持不变...
}
// 调用方代码
class Main {
public static void executeOrder(Order order) {
OrderProcessor processor = new OrderProcessor();
processor.processOrder(order);
// 移动过来的日志语句
System.out.println("Order processed: " + order.getId());
}
}
练习
基础练习题
-
移动日志语句
- 将 validateUser 方法中的日志输出移动到调用者
class UserValidator { public boolean validateUser(User user) { boolean isValid = checkCredentials(user); System.out.println("Validation result: " + isValid); // 需要移动 return isValid; } }
进阶练习题
-
条件语句移动
- 将 calculateDiscount 方法中的 VIP 检查逻辑移动到调用者
class PriceCalculator { public double calculateDiscount(User user, double amount) { if (user.isVIP()) { // 需要移动的条件判断 return amount * 0.2; } return amount * 0.1; } }
综合拓展练习题
-
多调用点差异化处理
- 重构 ReportGenerator 使其格式设置逻辑由不同调用者控制
class ReportGenerator { public String generateReport(Data data) { String content = buildContent(data); // 需要移动的格式设置 return "<html><body>" + content + "</body></html>"; } // 其他报告生成方法... }
代码审查要点
-
审查维度
- 单一职责原则:检查方法是否更聚焦核心职责
- 重复代码风险:评估多个调用点的代码重复可能性
- 接口合理性:验证新增参数/返回值的必要性
-
典型问题
- 过度移动导致调用点复杂度上升
- 未正确处理移动后的异常处理
- 多个调用点出现重复代码
-
优化建议
- 对多个调用点的公共逻辑使用「提取方法」
- 使用模板方法模式处理差异化需求
- 加强调用点的单元测试覆盖