| name | refactoring-patterns |
| description | 重构模式与方法论 —— 识别代码坏味道,安全地改善代码结构而不改变外部行为 |
| category | implementation |
| loading | on-demand |
| triggers | {"keywords":["重构","refactor","代码优化","整理代码","改结构"]} |
这是什么
重构是在不改变代码外部行为的前提下,改善其内部结构的过程。本 Skill 提供坏味道识别、安全重构手法和流程指导。
何时使用
- 代码出现明显的坏味道,如重复代码、过长函数、过大类
- 添加新功能前发现现有结构不适合扩展
- 代码审查中标记为需要重构
- 技术债务累积到影响开发效率
- 准备将原型代码转为生产代码
核心规则
- 重构前先写测试:没有测试覆盖的代码不应该重构。重构的安全网就是一套可以通过的测试。
- 小步提交:每次只做一个重构手法,提交后再做下一个。一个原子提交 = 一个重构手法。
- 重构和加功能不混在一起:一个提交要么重构(行为不变),要么加功能(结构不变),不同时做。
- 保持代码始终可运行:每一步重构后,测试必须全部通过。不要让代码在不可运行状态停留。
- 两顶帽子:开发时明确切换「加功能」和「重构」两种模式。加功能时不改现有测试,重构时不加新测试。
代码坏味道
结构层面
- 重复代码:相同或高度相似的逻辑出现在多处。最常见也最容易修复的坏味道。
- 过长函数:函数超过 50 行,承担了多个职责。Martin Fowler 建议超过 10 行就开始审视。
- 过大类:一个类承担了太多职责,字段和方法数量远超合理范围。
- 长参数列表:函数参数超过 5 个,说明函数职责不清或数据未合理分组。
- 发散式变化:修改一个类的原因有多种,违反单一职责原则。
逻辑层面
- 霰弹式修改:每次小改动需要同时修改多个类。
- 依恋情结:一个函数对另一个类的数据引用超过对自身类的引用。
- 数据泥团:多个数据项总是一起出现,应合并为独立对象。
- 基本类型偏执:用基本类型表示有业务含义的概念(用字符串表示电话号码,用整数表示金额)。
- Switch 语句:复杂的条件分支逻辑,应考虑多态替代。
安全重构手法
基本手法
- 提取函数:将一段代码片段提取为独立函数,以意图命名
- 内联函数:当函数体比函数名更清晰时,将函数体直接内联到调用处
- 提取变量:将复杂表达式提取为有意义的变量名
- 内联变量:当变量名不比表达式本身更清晰时,去除中间变量
对象间手法
- 移动函数:将函数移到它最常引用的类中
- 移动字段:将字段移到它最常被使用的类中
- 提炼类:当一个类做了两件事时,创建新类并移动相关字段和函数
- 隐藏委托关系:封装委托调用,让调用方不需要知道委托链
条件逻辑简化
- 分解条件表达式:将复杂的条件判断提取为独立函数
- 合并条件表达式:多个条件返回相同结果时合并为一个
- 以卫语句取代嵌套条件:用提前 return 替代深层嵌套
- 以多态取代条件表达式:用不同子类处理不同的条件分支
重构流程
- 识别目标:找到最影响当前开发效率的坏味道
- 确保测试:确认目标代码有足够的测试覆盖
- 选择手法:选取最简单的手法,一次只做一个
- 执行重构:实施变化,立即运行测试
- 检查结果:确认代码更清晰、测试仍通过
- 提交变更:小步提交,写清楚重构意图
- 重复:回到步骤 1,直到代码达到满意状态
遗留代码重构策略
处理缺乏测试的既有代码时,需要特殊策略:
- 接缝技术:识别代码中可以不修改代码就能改变行为的点(接缝),在接缝处引入测试
- 提取-覆盖:将需要修改的代码先提取为独立函数,为提取后的函数写测试,再重构
- 表征测试:记录当前行为作为期望行为,不判断对错。后续重构时确保行为不变
- 逐步包围:从边缘模块开始重构,逐渐向核心推进。避免一上来动核心
重构与设计模式
- 重构到模式:不是一开始就套用设计模式,而是发现坏味道后重构引入模式。模式是重构的目标,而非起点。
- 策略模式:替代复杂的条件分支
- 观察者模式:解耦事件发布者和处理者
- 工厂模式:封装对象创建逻辑,消除重复的 new 语句
- 适配器模式:统一第三方库或遗留接口
自动化重构工具
- IDE 重构菜单中的安全重构操作(重命名、提取函数、移动类)
- 静态分析工具自动识别坏味道并建议重构
- 代码格式化工具统一风格,消除风格争议
- 自动化测试框架确保重构过程中行为不变
参考标准
- Martin Fowler《重构:改善既有代码的设计》—— 重构领域权威著作
- Joshua Kerievsky《重构与模式》—— 将设计模式引入重构
- Michael Feathers《修改代码的艺术》—— 处理遗留代码的重构策略
- 代码复杂度指标:圈复杂度(Cyclomatic Complexity)不超过 10
- 认知复杂度(Cognitive Complexity)作为圈复杂度的补充度量