《Refactoring: Improving the Design of Existing Code》核心内容总结
一、书籍定位与目标读者
《Refactoring: Improving the Design of Existing Code》是Martin Fowler(马丁·福勒)的经典软件开发书籍,1999年由Addison-Wesley出版(2019年推出20周年纪念版)。其核心目标是帮助开发者系统性地改善既有代码的设计,提升代码的可读性、可维护性与扩展性,适合有一定编程经验、希望解决“代码腐化”问题的开发者阅读。
二、核心概念:重构的定义与价值
重构(Refactoring) 是本书的核心主题,定义为:在不改变代码外在行为的前提下,对代码内部结构进行修改,以提高其可理解性、降低修改成本。
重构的核心价值在于:
- 应对“代码腐化”:解决重复代码、过长函数、过大类等问题,避免代码变得难以理解和维护;
- 提升可扩展性:通过优化设计(如提取接口、使用多态),使代码更容易适应需求变化;
- 降低修改成本:减少因代码结构混乱导致的“霰弹式修改”(修改一处需要改动多处);
- 改善团队协作:清晰的代码结构让团队成员更容易理解彼此的工作,减少沟通成本。
三、重构的时机与原则
何时重构?
- 三次原则(Don Roberts准则):第一次做某件事时只管去做;第二次做类似的事会产生反感,但仍可接受;第三次再做类似的事,就应该重构;
- 添加新功能前:重构现有代码,使新功能的添加更简单(如提取公共方法、消除重复代码);
- 修补bug时:重构相关代码,避免bug再次出现(如简化复杂条件逻辑);
- 代码评审时:通过重构消除代码异味(如过长参数列表、数据泥团),提升代码质量。
重构的原则:
- 小步前进:每次重构只做一小部分,避免大规模修改导致的风险;
- 频繁测试:重构后立即运行测试,确保代码行为不变;
- 保留接口:尽量不修改公共接口(如方法签名),避免影响调用方;
- 避免过度设计:不要为了“完美”而引入不必要的抽象(如过早使用设计模式)。
四、常见代码“坏味道”与重构手法
本书详细列举了多种代码“坏味道”(Code Smells),并提供了对应的重构手法(Refactoring Techniques),以下是核心内容:
1. 重复代码(Duplicated Code)
问题:同一逻辑在多个地方重复(如不同子类的相同方法、不同模块的相同计算逻辑)。
重构手法:
- 提炼函数(Extract Method):将重复代码提取为一个独立函数,通过函数调用替代重复代码;
- 提炼类(Extract Class):如果重复代码涉及多个方法或字段,提取为一个新类,通过组合替代继承;
- 模板方法模式:如果重复代码有相似结构但细节不同,使用模板方法(父类定义算法骨架,子类实现具体步骤)。
2. 过长函数(Long Method)
问题:函数过长(通常超过20行),难以理解其意图。
重构手法:
- 提炼函数(Extract Method):将函数中的逻辑块(如循环、条件判断)提取为独立函数;
- 分解条件表达式(Decompose Conditional):将复杂的if-else或switch语句拆分为多个小函数;
- 以查询取代临时变量(Replace Temp with Query):将临时变量(如计算结果)替换为函数调用,减少函数参数。
3. 过长参数列表(Long Parameter List)
问题:函数参数过多(通常超过3个),难以理解和维护。
重构手法:
- 引入参数对象(Introduce Parameter Object):将相关参数封装为一个对象(如
OrderDetails),通过对象传递参数; - 以函数取代参数(Replace Parameter with Methods):如果参数是某个对象的属性,直接调用该对象的方法获取值;
- 保持对象完整(Preserve Whole Object):如果参数是某个对象的部分属性,直接传递整个对象。
4. 过大类(Large Class)
问题:类包含过多字段或方法,职责不单一(如“上帝类”)。
重构手法:
- 提炼类(Extract Class):将类的部分职责提取为新类(如将“订单处理”和“库存管理”分离);
- 提炼子类(Extract Subclass):如果类的部分行为只适用于特定场景,提取为子类(如
RegularOrder和VIPOrder); - 接口隔离(Interface Segregation):如果类实现了多个不相关的接口,将其拆分为多个小接口。
5. 发散式变化(Divergent Change)
问题:一个类因不同原因频繁修改(如“订单类”既修改价格计算逻辑,又修改库存逻辑)。
重构手法:
- 提炼类(Extract Class):将不同职责的代码分离到不同类中(如
PriceCalculator和InventoryManager); - 细粒度化(Split Responsibility):将类的方法拆分为更小的、单一职责的方法。
6. 霰弹式修改(Shotgun Surgery)
问题:修改一个功能需要改动多个类(如“修改订单状态”需要修改Order、Inventory、Payment等多个类)。
重构手法:
- 搬移函数(Move Method):将相关方法从分散的类移动到同一个类中(如将“计算订单总价”方法从
Order移动到OrderCalculator); - 收敛类(Consolidate Class):将分散的类合并为一个类,减少类之间的依赖。
7. 依恋情结(Feature Envy)
问题:一个类的方法过度依赖另一个类的数据(如Order类频繁访问Customer类的address字段)。
重构手法:
- 搬移函数(Move Method):将依赖其他类数据的方法移动到该类中(如将“获取客户地址”的方法从
Order移动到Customer); - 隐藏委托关系(Hide Delegate):通过代理模式隐藏类之间的委托关系(如
Order类通过Customer类的代理获取地址)。
8. 数据泥团(Data Clumps)
问题:相同的数据在多个地方重复出现(如name、address、phone在多个类中重复)。
重构手法:
- 提炼类(Extract Class):将数据封装为一个对象(如
CustomerInfo),通过对象传递数据; - 以函数取代参数(Replace Parameter with Methods):如果数据是某个对象的属性,直接调用该对象的方法获取值。
9. 基本类型偏执(Primitive Obsession)
问题:使用基本类型(如int、String)代替对象,导致代码冗余(如用int表示“性别”,用String表示“地址”)。
重构手法:
- 以对象取代基本类型(Replace Data Value with Object):将基本类型封装为对象(如
Gender、Address),通过对象的方法处理数据; - 枚举类型(Enum):如果基本类型表示有限集合(如性别、状态),使用枚举类型替代。
10. switch语句过多(Switch Statements)
问题:大量使用switch语句处理多分支逻辑(如根据订单类型计算价格)。
重构手法:
- 多态(Polymorphism):用子类替代switch语句(如
Order类的子类RegularOrder、VIPOrder实现各自的calculatePrice方法); - 策略模式(Strategy Pattern):将分支逻辑封装为独立的策略类,通过上下文类选择策略。
五、重构的实践建议
- 建立测试体系:重构前确保有完善的单元测试,重构后立即运行测试,避免引入bug;
- 使用自动化工具:利用IDE(如IntelliJ IDEA、Eclipse)的重构工具(如“Extract Method”“Rename”),减少手动修改的错误;
- 遵循命名规范:函数名应清晰表达其意图(如
calculateTotalPrice比calc更易理解); - 避免过度重构:不要为了“完美”而重构,优先解决影响当前开发的问题。
六、总结
《Refactoring: Improving the Design of Existing Code》是软件开发领域的经典之作,其核心思想是“通过重构改善代码设计,而非通过重写解决所有问题”。书中提供的重构手法和“坏味道”识别技巧,是开发者应对“代码腐化”的有力武器。通过持续重构,开发者可以保持代码的健康状态,提升开发效率,降低维护成本。