代码重构的核心原则
保持功能不变的前提下改善代码结构,提高可读性、可维护性和可扩展性。重构不是添加新功能,而是优化现有代码。
识别重构时机
重复代码超过三处时应考虑提取公共方法。长方法(通常超过20行)需要拆分为更小的单元。嵌套过深的控制结构(if/for超过3层)需要扁平化。
常用重构技术
提取方法
将代码片段移至新方法,使用描述性名称:
java
// 重构前
void printOwing() {
printBanner();
System.out.println("name: " + name);
System.out.println("amount: " + getAmount());
}
// 重构后
void printOwing() {
printBanner();
printDetails(getAmount());
}
void printDetails(double amount) {
System.out.println("name: " + name);
System.out.println("amount: " + amount);
}
内联方法
简单方法直接展开到调用处:
python
# 重构前
def get_rating():
return 2 if more_than_five_late_deliveries() else 1
# 重构后
def get_rating():
return 2 if number_of_late_deliveries > 5 else 1
替换临时变量
用查询方法替代中间变量:
javascript
// 重构前
const basePrice = quantity * itemPrice;
if (basePrice > 1000) {...}
// 重构后
if (basePrice() > 1000) {...}
function basePrice() {
return quantity * itemPrice;
}
面向对象重构
提炼类
当类承担过多职责时拆分:
csharp
// 重构前
class Customer {
void SaveToDatabase() {...}
void GenerateReport() {...}
}
// 重构后
class CustomerRepository {
void Save(Customer c) {...}
}
class ReportGenerator {
void Generate(Customer c) {...}
}
引入多态替代条件语句
用继承体系处理复杂分支:
java
// 重构前
double getSpeed() {
switch (type) {
case EUROPEAN: return baseSpeed();
case AFRICAN: return baseSpeed() - loadFactor;
case NORWEGIAN: return (isNailed) ? 0 : baseSpeed();
}
}
// 重构后
abstract class Bird {
abstract double getSpeed();
}
class EuropeanBird extends Bird {
double getSpeed() { return baseSpeed(); }
}
重构保障措施
建立自动化测试套件覆盖核心功能。使用版本控制系统保证可回退。遵循小步修改原则,每次提交只完成一个明确的重构目标。
性能考量
重构可能暂时影响性能,但优化后的结构更利于后续性能调优。避免在性能关键路径上过度抽象,必要时通过基准测试验证。
代码坏味道清单
- 神秘命名(Unclear Names)
- 过长参数列表(Long Parameter List)
- 数据泥团(Data Clumps)
- 基本类型偏执(Primitive Obsession)
- 重复代码(Duplicated Code)
- 过长函数(Long Method)
- 过大类(Large Class)
- 发散式变化(Divergent Change)
- 霰弹式修改(Shotgun Surgery)
- 特性依恋(Feature Envy)
重构工具支持
现代IDE如IntelliJ IDEA、Visual Studio提供自动化重构功能。静态分析工具(SonarQube)可识别需要重构的代码段。代码格式化工具(Prettier)保持风格一致。