refactoring-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRefactoring Patterns Framework
重构模式框架
A disciplined approach to improving the internal structure of existing code without changing its observable behavior. Apply these named transformations when reviewing code, reducing technical debt, or preparing code for new features. Every refactoring follows the same loop: verify tests pass, apply one small structural change, verify tests still pass.
这是一种严谨的方法,用于改进现有代码的内部结构,同时不改变其可观测的外部行为。在评审代码、减少技术债务或为新增功能准备代码时,可应用这些命名转换手法。每一次重构都遵循相同的循环:验证测试通过,应用一项小型结构变更,再次验证测试通过。
Core Principle
核心原则
Refactoring is not rewriting. It is a sequence of small, behavior-preserving transformations, each backed by tests. You never change what the code does -- you change how the code is organized. The discipline of taking tiny verified steps is what makes refactoring safe. Big-bang rewrites fail because they combine structural change with behavioral change, making it impossible to know which broke things.
The foundation: Bad code is not a character flaw -- it is a natural consequence of delivering features under time pressure. Code smells are objective signals that structure has degraded. Named refactorings are the proven mechanical recipes for fixing each smell. The catalog of smells tells you where to look; the catalog of refactorings tells you what to do.
重构并非重写。它是一系列小型、保留行为的转换操作,每一步都有测试作为保障。 你永远不会改变代码的功能——只会改变代码的组织方式。采用微小且经过验证的步骤进行操作,是重构安全性的关键所在。大爆炸式重写之所以失败,是因为它将结构变更与行为变更混为一谈,导致无法定位问题根源。
基础认知: 糟糕的代码并非编写者的能力缺陷——它是在时间压力下交付功能时的自然结果。代码坏味道是结构退化的客观信号。命名重构手法是经过验证的、可解决各类坏味道的标准化方案。坏味道目录告诉你需要关注哪里,而重构手法目录告诉你该做什么。
Scoring
评分标准
Goal: 10/10. When reviewing or refactoring code, rate the structural quality 0-10 based on adherence to the principles below. A 10/10 means: no obvious smells remain, each function does one thing, names reveal intent, duplication is eliminated, and the test suite covers the refactored paths. Always provide the current score and specific refactorings needed to reach 10/10.
目标:10/10。 在评审或重构代码时,根据以下原则对结构质量进行0-10分的评分。10分意味着:不存在明显的代码坏味道,每个函数只负责一件事,命名能清晰表达意图,消除了重复代码,测试套件覆盖了所有重构路径。请始终给出当前分数,以及达到10分所需的具体重构手法。
The Refactoring Patterns Framework
重构模式框架
Six areas of focus for systematically improving code structure:
系统改进代码结构的六大核心方向:
1. Code Smells as Triggers
1. 以代码坏味道为触发点
Core concept: Code smells are surface indicators of deeper structural problems. They are not bugs -- the code works -- but they signal that the design is making the code harder to understand, extend, or maintain. Each smell maps to one or more named refactorings that fix it.
Why it works: Without a shared vocabulary of smells, code review devolves into subjective "I don't like this." Named smells give teams objective criteria: "This is Feature Envy -- the method uses six fields from another class and only one of its own." The name points directly to the fix.
Key insights:
- Smells cluster into five families: Bloaters, Object-Orientation Abusers, Change Preventers, Dispensables, and Couplers
- Long Method is the most common smell and the gateway to most other refactorings
- Duplicate Code is the single biggest driver of maintenance cost
- A method that needs a comment to explain what it does is a smell -- extract and name the block instead
- Shotgun Surgery (one change requires edits in many classes) and Divergent Change (one class changes for many reasons) are opposites that both signal misplaced responsibilities
- Primitive Obsession -- using raw strings, ints, or arrays instead of small domain objects -- causes errors and duplication throughout the codebase
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Method > 10 lines | Extract Method | Pull the loop body into |
| Class > 200 lines | Extract Class | Move shipping logic into a |
| Switch on type code | Replace Conditional with Polymorphism | Create subclasses for each order type |
| Multiple methods use same params | Introduce Parameter Object | Group |
| Method uses another object's data | Move Method | Move |
| Copy-pasted logic | Extract Method + Pull Up Method | Share via a common method or base class |
See: references/smell-catalog.md
核心概念: 代码坏味道是深层结构问题的表面征兆。它们并非bug——代码仍能正常工作——但预示着当前设计会让代码更难理解、扩展或维护。每种坏味道都对应一种或多种可解决它的命名重构手法。
为何有效: 如果没有统一的坏味道术语体系,代码评审会退化为主观的“我不喜欢这段代码”。命名的坏味道为团队提供了客观标准:“这是特性依恋(Feature Envy)——该方法使用了另一个类的六个字段,而仅使用了自身的一个字段。” 这个名称直接指向了修复方案。
关键见解:
- 坏味道可分为五大类:臃肿类(Bloaters)、面向对象滥用类(Object-Orientation Abusers)、变更阻碍类(Change Preventers)、冗余类(Dispensables)、耦合类(Couplers)
- 过长方法(Long Method)是最常见的坏味道,也是大多数重构的起点
- 重复代码(Duplicate Code)是维护成本居高不下的最大诱因
- 如果某个方法需要注释来解释它做了什么,这就是一种坏味道——应将代码块提取为方法并使用注释作为方法名
- 霰弹式修改(Shotgun Surgery,一项变更需要修改多个类)和发散式变更(Divergent Change,一个类因多种原因被修改)是对立的两种情况,但都表明职责分配不当
- 原始类型痴迷(Primitive Obsession,使用原始字符串、整数或数组而非小型领域对象)会在整个代码库中引发错误和重复
代码应用场景:
| 场景 | 重构手法 | 示例 |
|---|---|---|
| 方法行数>10行 | Extract Method | 将循环体提取到 |
| 类行数>200行 | Extract Class | 将物流逻辑迁移到 |
| 基于类型码的Switch语句 | Replace Conditional with Polymorphism | 为每种订单类型创建子类 |
| 多个方法使用相同参数 | Introduce Parameter Object | 将 |
| 方法使用另一个对象的数据 | Move Method | 将 |
| 复制粘贴的逻辑 | Extract Method + Pull Up Method | 通过公共方法或基类共享逻辑 |
参考:references/smell-catalog.md
2. Composing Methods
2. 方法组合
Core concept: Most refactoring starts here. Long methods are broken into smaller, well-named pieces. Each extracted piece should do one thing and its name should say what that thing is. The goal is methods you can read like prose -- a sequence of high-level steps, each delegating to a clearly named helper.
Why it works: Short methods with intention-revealing names eliminate the need for comments, make bugs obvious (each method is small enough to verify at a glance), and enable reuse. The cognitive cost of a method call is near zero when the name tells you everything.
Key insights:
- Extract Method is the single most important refactoring -- master it first
- If you feel the urge to write a comment, extract the code block and use the comment as the method name
- Inline Method when a method body is as clear as the name -- indirection without value is noise
- Replace Temp with Query when a temporary variable holds a computed value that is used in multiple places
- Split Temporary Variable when one variable is reused for two different purposes
- Replace Method with Method Object when a method is too tangled to extract from (many local variables referencing each other)
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Block with a comment | Extract Method | |
| Temp used once | Inline Variable | Remove |
| Temp used in multiple places | Replace Temp with Query | Replace |
| Temp assigned twice for different reasons | Split Temporary Variable | Introduce |
| Trivial delegating method | Inline Method | Inline |
| Complex method with many locals | Replace Method with Method Object | Move the method into its own class where locals become fields |
See: references/composing-methods.md
核心概念: 大多数重构都从这里开始。将过长的方法拆分为更小、命名清晰的片段。每个提取出的片段应只负责一件事,且其名称应明确表达该职责。目标是让方法像散文一样易读——由一系列高层步骤组成,每个步骤都委托给命名清晰的辅助方法。
为何有效: 短小且意图明确的方法无需注释,能让bug无所遁形(每个方法足够小,可快速验证),并支持代码复用。当方法名能告诉你所有信息时,方法调用的认知成本几乎为零。
关键见解:
- Extract Method是最重要的重构手法——首先掌握它
- 如果你想写注释,就将对应的代码块提取为方法,并将注释作为方法名
- 当方法体与方法名一样清晰时,使用Inline Method(内联方法)——无意义的间接性是冗余噪声
- 当临时变量存储的计算值被多处使用时,使用Replace Temp with Query(以查询取代临时变量)
- 当一个变量被用于两种不同用途时,使用Split Temporary Variable(拆分临时变量)
- 当方法过于复杂无法直接提取(存在大量相互引用的局部变量)时,使用Replace Method with Method Object(以方法对象取代方法)
代码应用场景:
| 场景 | 重构手法 | 示例 |
|---|---|---|
| 带有注释的代码块 | Extract Method | |
| 临时变量仅使用一次 | Inline Variable | 如果 |
| 临时变量被多处使用 | Replace Temp with Query | 将 |
| 临时变量被赋予两种不同用途的值 | Split Temporary Variable | 引入 |
| 仅做简单委托的方法 | Inline Method | 如果 |
| 包含大量局部变量的复杂方法 | Replace Method with Method Object | 将该方法移至独立类中,局部变量变为类的字段 |
参考:references/composing-methods.md
3. Moving Features Between Objects
3. 在对象间转移特性
Core concept: The key decision in object-oriented design is where to put responsibilities. When a method or field is in the wrong class -- evidenced by Feature Envy, excessive coupling, or unbalanced class sizes -- move it to where it belongs.
Why it works: Well-placed responsibilities reduce coupling and increase cohesion. When a method lives in the class whose data it uses, changes to that data affect only one class. Misplaced methods create invisible dependencies that cause Shotgun Surgery.
Key insights:
- Move Method when a method uses more features of another class than its own
- Move Field when a field is used more by another class than the class it lives in
- Extract Class when one class does two things -- split along the axis of change
- Inline Class when a class does too little to justify its existence
- Hide Delegate to enforce the Law of Demeter -- a client shouldn't navigate a chain of objects
- Remove Middle Man when a class does nothing but forward calls
- The tension between Hide Delegate and Remove Middle Man is resolved case by case: hide the delegate when the chain is unstable; remove the middle man when forwarding becomes the entire class
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Method envies another class | Move Method | Move |
| Field used by another class constantly | Move Field | Move |
| God class with 500+ lines | Extract Class | Pull |
| Tiny class with one field | Inline Class | Merge |
| Client calls a.getB().getC() | Hide Delegate | Add |
| Class only forwards calls | Remove Middle Man | Let client call the delegate directly |
See: references/moving-features.md
核心概念: 面向对象设计中的关键决策是职责的归属。当某个方法或字段位于错误的类中(表现为特性依恋、过度耦合或类大小失衡)时,应将其移至合适的类中。
为何有效: 职责分配合理能降低耦合度并提高内聚性。当方法位于其使用数据的类中时,数据变更只会影响一个类。错误放置的方法会产生隐形依赖,导致霰弹式修改。
关键见解:
- 当方法使用另一个类的特性多于自身类时,使用Move Method(搬移方法)
- 当字段被另一个类使用的次数多于其所属类时,使用Move Field(搬移字段)
- 当一个类承担两种职责时,使用Extract Class(提取类)——按变更维度拆分
- 当一个类的职责少到不足以独立存在时,使用Inline Class(内联类)
- 使用Hide Delegate(隐藏委托)来遵循迪米特法则——客户端不应遍历对象链
- 当一个类仅做转发调用时,使用Remove Middle Man(移除中间人)
- Hide Delegate和Remove Middle Man的权衡需视情况而定:当对象链不稳定时隐藏委托;当转发成为类的全部职责时移除中间人
代码应用场景:
| 场景 | 重构手法 | 示例 |
|---|---|---|
| 方法依恋另一个类 | Move Method | 将 |
| 字段被另一个类频繁使用 | Move Field | 将 |
| 行数超500行的上帝类 | Extract Class | 将 |
| 仅含一个字段的小型类 | Inline Class | 如果 |
客户端调用 | Hide Delegate | 添加 |
| 类仅做转发调用 | Remove Middle Man | 让客户端直接调用委托对象 |
参考:references/moving-features.md
4. Organizing Data
4. 数据组织
Core concept: Raw data -- magic numbers, exposed fields, type codes represented as integers, parallel arrays -- creates subtle bugs and scatters domain knowledge. Replace primitive representations with objects that encapsulate behavior and enforce invariants.
Why it works: An representing a currency amount has no concept of rounding rules, currency codes, or formatting. A object encapsulates all of that. When domain concepts are represented as first-class objects, business rules live in one place, validation happens automatically, and the type system catches errors at compile time.
intMoneyKey insights:
- Replace Magic Number with Symbolic Constant as the simplest data refactoring -- it names the intent
- Replace Data Value with Object (Primitive Obsession cure) -- wrap strings and numbers in domain objects (,
EmailAddress,Money)Temperature - Encapsulate Field -- never expose a raw field; a getter/setter allows you to add validation, logging, or computation later
- Encapsulate Collection -- return an unmodifiable view; never let callers mutate your internal list
- Replace Type Code with Subclasses when the type code affects behavior; use Strategy when subclassing is impractical
- Change Value to Reference when you need identity semantics (one shared object, not copies)
Customer
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Replace Magic Number with Symbolic Constant | |
| Replace Data Value with Object | Create |
| Public field | Encapsulate Field | Replace |
| Getter returns mutable list | Encapsulate Collection | Return |
| Replace Type Code with Subclasses | |
| Duplicated customer records | Change Value to Reference | Share one |
See: references/organizing-data.md
核心概念: 原始数据——魔法数字、暴露的字段、用整数表示的类型码、并行数组——会引发隐蔽的bug,并分散领域知识。应使用封装行为、强制不变量的对象替代原始数据表示。
为何有效: 表示货币金额的类型不具备舍入规则、货币代码或格式化的概念。而对象封装了所有这些逻辑。当领域概念被表示为一等对象时,业务规则集中存放,验证自动执行,类型系统可在编译时捕获错误。
intMoney关键见解:
- Replace Magic Number with Symbolic Constant(以符号常量取代魔法数字)是最简单的数据重构手法——它能明确表达意图
- Replace Data Value with Object(以对象取代数据值,解决原始类型痴迷问题)——将字符串和数字包装为领域对象(如、
EmailAddress、Money)Temperature - Encapsulate Field(封装字段)——永远不要暴露原始字段;getter/setter允许你后续添加验证、日志或计算逻辑
- Encapsulate Collection(封装集合)——返回不可修改的视图;永远不要让调用者修改你的内部列表
- 当类型码影响行为时,使用Replace Type Code with Subclasses(以子类取代类型码);当子类化不可行时使用策略模式(Strategy)
- 当需要身份语义时,使用Change Value to Reference(以引用取代值对象)——使用一个共享的对象,而非多个副本
Customer
代码应用场景:
| 场景 | 重构手法 | 示例 |
|---|---|---|
| Replace Magic Number with Symbolic Constant | 改为 |
| Replace Data Value with Object | 创建带验证逻辑的 |
| 公共字段 | Encapsulate Field | 将 |
| Getter返回可变列表 | Encapsulate Collection | 返回 |
基于 | Replace Type Code with Subclasses | |
| 重复的客户记录 | Change Value to Reference | 通过注册表共享单个 |
参考:references/organizing-data.md
5. Simplifying Conditional Logic
5. 简化条件逻辑
Core concept: Complex conditionals -- deeply nested if/else trees, long switch statements, null checks scattered everywhere -- are the hardest code to read and the most likely to contain bugs. Named refactorings decompose, consolidate, and replace conditionals with clearer structures.
Why it works: A conditional with six branches and nested sub-conditions requires the reader to simulate every path mentally. Decomposing the condition into well-named methods makes each branch self-documenting. Replacing conditionals with polymorphism eliminates entire categories of "forgot to handle this case" bugs.
Key insights:
- Decompose Conditional: extract the condition, the then-branch, and the else-branch into named methods
- Consolidate Conditional Expression: merge multiple conditions that lead to the same result into one named check
- Replace Nested Conditional with Guard Clauses: handle edge cases early and return, leaving the main path unindented
- Replace Conditional with Polymorphism: the gold standard for type-based conditionals -- each type knows its own behavior
- Introduce Special Case (Null Object): eliminate checks by providing an object that represents "nothing" with safe default behavior
if (x == null) - Introduce Assertion: make assumptions explicit so they fail fast in development
Code applications:
| Context | Pattern | Example |
|---|---|---|
Long | Decompose Conditional | Extract |
Multiple | Consolidate Conditional | Combine into |
Deeply nested | Replace with Guard Clauses | Check edge cases first, return early, flatten the main path |
| Switch on object type | Replace Conditional with Polymorphism | Each type implements its own |
| Introduce Special Case | Create |
| Hidden assumption in code | Introduce Assertion | |
See: references/simplifying-conditionals.md
核心概念: 复杂的条件语句——深层嵌套的if/else树、冗长的Switch语句、随处可见的空值检查——是最难阅读的代码,也最容易包含bug。命名重构手法可将条件逻辑分解、合并,替换为更清晰的结构。
为何有效: 包含六个分支和嵌套子条件的条件语句,要求读者在脑中模拟所有路径。将条件分解为命名方法后,每个分支都能自我解释。用多态替代条件语句可消除一整类“忘记处理该情况”的bug。
关键见解:
- Decompose Conditional(分解条件表达式):将条件、then分支、else分支提取为命名方法
- Consolidate Conditional Expression(合并条件表达式):将多个导致相同结果的条件合并为一个命名检查
- Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件):提前处理边缘情况并返回,使主路径代码无缩进
- Replace Conditional with Polymorphism(以多态取代条件语句):基于类型的条件语句的黄金解决方案——每个类型都知晓自身行为
- Introduce Special Case(引入特例,即空对象模式):通过提供代表“无”的对象并实现安全默认行为,消除检查
if (x == null) - Introduce Assertion(引入断言):明确假设,使其在开发阶段快速失败
代码应用场景:
| 场景 | 重构手法 | 示例 |
|---|---|---|
带有复杂条件的长 | Decompose Conditional | 提取 |
多个 | Consolidate Conditional | 合并为 |
深层嵌套的 | Replace with Guard Clauses | 先检查边缘情况并提前返回,扁平化主路径代码 |
| 基于对象类型的Switch语句 | Replace Conditional with Polymorphism | 每个类型实现自身的 |
到处都是 | Introduce Special Case | 创建 |
| 代码中的隐藏假设 | Introduce Assertion | 在方法入口添加 |
参考:references/simplifying-conditionals.md
6. Safe Refactoring Workflow
6. 安全重构工作流
Core concept: Refactoring is only safe when wrapped in tests. The workflow is mechanical: run tests (green), apply one small transformation, run tests (green), commit. If tests go red, revert the last change -- don't debug a broken refactoring.
Why it works: Small steps make it trivial to find what went wrong (it was the last thing you did). Reverting a failed step costs seconds. Debugging a failed big-bang rewrite costs days. Frequent commits create save points you can return to.
Key insights:
- The refactoring cycle: test -> refactor -> test -> commit (repeat)
- Rule of Three: tolerate duplication once, note it twice, refactor on the third occurrence
- Preparatory refactoring: restructure code to make the feature easy before adding the feature
- Comprehension refactoring: refactor to understand code as you read it -- leave it clearer than you found it
- Litter-pickup refactoring: small improvements whenever you touch a file (Boy Scout Rule)
- When NOT to refactor: when it's easier to rewrite from scratch, when there are no tests and adding them first isn't feasible, or when the code will be deleted soon
- Refactoring and performance: refactor for clarity first, then profile and optimize the measured bottleneck -- refactored code is easier to tune because the hot path is isolated
- Branch by Abstraction and Parallel Change enable large refactorings in production systems without feature branches
Code applications:
| Context | Pattern | Example |
|---|---|---|
| About to add a feature | Preparatory Refactoring | Extract method to make new feature's insertion point clean |
| Reading unfamiliar code | Comprehension Refactoring | Rename variables and extract methods to understand intent |
| Saw a small issue while working | Litter-Pickup Refactoring | Fix the smell before moving on (Boy Scout Rule) |
| Third copy of same logic | Rule of Three | Extract the shared logic into a common method |
| Large API change in production | Branch by Abstraction | Introduce abstraction layer, migrate callers, remove old path |
| Renaming a widely-used method | Parallel Change | Add new name, deprecate old, migrate callers, remove old |
See: references/refactoring-workflow.md
核心概念: 只有在测试的保障下,重构才是安全的。工作流是机械性的:运行测试(绿色),应用一项小型转换,运行测试(绿色),提交代码。如果测试变红,回滚上一次变更——不要调试失败的重构。
为何有效: 小型步骤让定位问题变得微不足道(问题就是你上一步做的变更)。回滚失败的步骤只需几秒钟,而调试失败的大爆炸式重写则需要数天。频繁提交会创建可回溯的保存点。
关键见解:
- 重构循环:测试→重构→测试→提交(重复)
- 三次原则(Rule of Three):第一次重复时容忍,第二次重复时记录,第三次重复时重构
- 预备性重构:在添加功能之前重构代码,使新增功能的实现更简单
- 理解性重构:在阅读代码时进行重构,让代码比你发现它时更清晰
- 随手重构:每次修改文件时进行小型改进(童子军规则:让营地比你发现时更干净)
- 不应重构的场景:从头重写更简单时;没有测试且无法先添加测试时;代码即将被删除时
- 重构与性能:先重构以提升清晰度,再通过性能分析优化已确认的瓶颈——重构后的代码更易于调优,因为热点路径已被隔离
- 抽象分支(Branch by Abstraction)和平行变更(Parallel Change)可在生产系统中实现大型重构,无需使用功能分支
代码应用场景:
| 场景 | 模式 | 示例 |
|---|---|---|
| 即将添加新功能 | 预备性重构 | 提取方法,使新功能的插入点更简洁 |
| 阅读不熟悉的代码 | 理解性重构 | 重命名变量、提取方法以明确代码意图 |
| 工作时发现小型问题 | 随手重构 | 修复坏味道后再继续工作(童子军规则) |
| 第三次出现相同逻辑 | 三次原则 | 将共享逻辑提取到公共方法中 |
| 生产系统中的大型API变更 | 抽象分支 | 引入抽象层,迁移调用者,移除旧路径 |
| 重命名被广泛使用的方法 | 平行变更 | 添加新方法名,标记旧方法为废弃,迁移调用者,最后删除旧方法 |
参考:references/refactoring-workflow.md
Common Mistakes
常见错误
| Mistake | Why It Fails | Fix |
|---|---|---|
| Refactoring without tests | No safety net -- you can't tell if behavior changed | Write characterization tests first, then refactor |
| Big-bang rewrite instead of incremental steps | Combines structural and behavioral changes; impossible to debug | Take the smallest step possible, run tests after each |
| Refactoring and adding features at the same time | Two hats at once -- you can't verify either change in isolation | Separate the hats: refactor first (commit), then add feature (commit) |
| Renaming without updating all callers | Breaks the build or introduces dead code | Use IDE rename refactoring; search for all references |
| Extracting too many tiny methods | Creates indirection without clarity when names are poor | Each extracted method must have a name that removes the need to read the body |
| Ignoring the smell catalog | Reinventing fixes instead of applying proven recipes | Learn the named smells; each one maps to specific refactorings |
| Refactoring code that will be deleted | Wasted effort -- polish on condemned code | Ask first: is this code's lifespan long enough to justify the investment? |
| Optimizing prematurely during refactoring | Conflates clarity with performance; optimized code is often harder to read | Refactor for clarity first, then profile, then optimize the measured hot path only |
| 错误 | 失败原因 | 修复方案 |
|---|---|---|
| 无测试情况下重构 | 没有安全保障——无法判断行为是否改变 | 先编写或修复测试,再进行重构 |
| 采用大爆炸式重写而非增量步骤 | 混合了结构变更与行为变更,无法调试 | 采用尽可能小的步骤,每步后运行测试 |
| 重构与添加功能同时进行 | 同时扮演两种角色——无法单独验证任何一项变更 | 分离角色:先重构(提交),再添加功能(提交) |
| 重命名时未更新所有调用者 | 导致构建失败或引入死代码 | 使用IDE的重命名重构功能;搜索所有引用 |
| 提取过多过小的方法 | 当命名不佳时,会产生无意义的间接性 | 每个提取的方法必须有一个无需阅读方法体就能理解其意图的名称 |
| 忽略坏味道目录 | 重复发明修复方案,而非应用经过验证的成熟手法 | 学习命名的坏味道;每种坏味道都对应特定的重构手法 |
| 重构即将被删除的代码 | 浪费精力——为即将废弃的代码做优化 | 先确认:这段代码的生命周期是否足够长,值得投入时间重构? |
| 重构时过早优化 | 将清晰度与性能混淆;优化后的代码通常更难阅读 | 先重构以提升清晰度,再进行性能分析,仅优化已确认的热点路径 |
Quick Diagnostic
快速诊断
| Question | If No | Action |
|---|---|---|
| Do tests pass before you start? | You have no safety net | Write or fix tests first -- do not refactor without green tests |
| Can you name the smell you're fixing? | You're refactoring by instinct, not by catalog | Identify the smell from the catalog, then apply its prescribed refactoring |
| Is each method under ~10 lines? | Long Methods are likely present | Apply Extract Method to break long methods into named steps |
| Does each class have a single reason to change? | Divergent Change or Large Class smell | Apply Extract Class to separate responsibilities |
| Are there duplicated code blocks? | Duplicate Code is the most expensive smell | Extract shared logic into a common method or base class |
| Do conditionals use polymorphism where appropriate? | Switch Statements or complex | Apply Replace Conditional with Polymorphism |
| Are you committing after each refactoring step? | You risk losing work and mixing changes | Commit after every green-to-green transformation |
| Is the code easier to read after your change? | The refactoring may have added complexity | Revert and try a different approach |
| 问题 | 如果答案为否 | 行动 |
|---|---|---|
| 开始重构前测试是否通过? | 你没有安全保障 | 先编写或修复测试——不要在测试未通过的情况下进行重构 |
| 你能说出正在修复的坏味道名称吗? | 你是凭直觉重构,而非依据标准目录 | 从目录中识别对应的坏味道,再应用其指定的重构手法 |
| 每个方法的行数是否都在~10行以内? | 可能存在过长方法 | 应用Extract Method将过长方法拆分为命名步骤 |
| 每个类是否只有一个变更原因? | 存在发散式变更或过大类的坏味道 | 应用Extract Class分离职责 |
| 是否存在重复的代码块? | 存在重复代码这种高成本的坏味道 | 将共享逻辑提取到公共方法或基类中 |
| 条件语句是否在合适的场景下使用了多态? | 仍存在Switch语句或复杂的 | 应用Replace Conditional with Polymorphism |
| 每次重构步骤后是否都提交了代码? | 你可能会丢失工作成果,或混合不同变更 | 每次从绿色到绿色的转换后都提交代码 |
| 变更后的代码是否更易读? | 重构可能增加了复杂度 | 回滚并尝试其他方法 |
Reference Files
参考文件
- smell-catalog.md: Comprehensive catalog of code smells organized by family -- Bloaters, Object-Orientation Abusers, Change Preventers, Dispensables, and Couplers -- with detection heuristics and fix mappings
- composing-methods.md: Extract Method, Inline Method, Extract Variable, Inline Variable, Replace Temp with Query, Split Temporary Variable, Remove Assignments to Parameters, Replace Method with Method Object -- motivation, mechanics, and examples
- moving-features.md: Move Method, Move Field, Extract Class, Inline Class, Hide Delegate, Remove Middle Man -- when and how to redistribute responsibilities between objects
- organizing-data.md: Replace Data Value with Object, Change Value to Reference, Replace Array with Object, Replace Magic Number, Encapsulate Field, Encapsulate Collection, Replace Type Code with Class/Subclasses/Strategy
- simplifying-conditionals.md: Decompose Conditional, Consolidate Conditional, Replace Nested Conditional with Guard Clauses, Replace Conditional with Polymorphism, Introduce Special Case, Introduce Assertion -- with before/after examples
- refactoring-workflow.md: The refactoring cycle, when to refactor, when NOT to refactor, refactoring and performance, Branch by Abstraction, Parallel Change
- smell-catalog.md: 按类别(臃肿类、面向对象滥用类、变更阻碍类、冗余类、耦合类)组织的代码坏味道综合目录,包含检测方法和修复映射
- composing-methods.md: Extract Method、Inline Method、Extract Variable、Inline Variable、Replace Temp with Query、Split Temporary Variable、Remove Assignments to Parameters、Replace Method with Method Object——动机、步骤和示例
- moving-features.md: Move Method、Move Field、Extract Class、Inline Class、Hide Delegate、Remove Middle Man——何时以及如何在对象间重新分配职责
- organizing-data.md: Replace Data Value with Object、Change Value to Reference、Replace Array with Object、Replace Magic Number、Encapsulate Field、Encapsulate Collection、Replace Type Code with Class/Subclasses/Strategy
- simplifying-conditionals.md: Decompose Conditional、Consolidate Conditional、Replace Nested Conditional with Guard Clauses、Replace Conditional with Polymorphism、Introduce Special Case、Introduce Assertion——包含前后对比示例
- refactoring-workflow.md: 重构循环、何时重构、何时不应重构、重构与性能、抽象分支、平行变更
Further Reading
延伸阅读
This skill is based on the definitive guide to improving the design of existing code:
- "Refactoring: Improving the Design of Existing Code (2nd Edition)" by Martin Fowler
- "Working Effectively with Legacy Code" by Michael Feathers (companion for code without tests)
- "Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin (complementary naming and style principles)
本内容基于改进现有代码设计的权威指南:
- 《重构:改善既有代码的设计(第2版)》 作者:Martin Fowler
- 《修改代码的艺术》 作者:Michael Feathers(针对无测试代码的配套指南)
- 《代码整洁之道》 作者:Robert C. Martin(补充命名和风格原则)
About the Author
关于作者
Martin Fowler is the Chief Scientist at Thoughtworks and one of the most influential voices in software engineering. He is the author of Refactoring: Improving the Design of Existing Code (1999, 2nd edition 2018), which introduced the concept of named, catalog-based refactoring transformations to mainstream software development. Fowler is also the author of Patterns of Enterprise Application Architecture, UML Distilled, and numerous influential articles on software design, agile methodology, and continuous delivery. He was a signatory of the Agile Manifesto and has spent decades advocating for evolutionary design -- the practice of continuously improving code structure through disciplined, incremental refactoring rather than upfront big design. His refactoring catalog, originally written in Java, has been adapted to virtually every programming language and is built into the automated refactoring tools of every major IDE.
Martin Fowler 是Thoughtworks的首席科学家,也是软件工程领域最具影响力的声音之一。他是《重构:改善既有代码的设计》(1999年首版,2018年第2版)的作者,该书将命名的、基于目录的重构转换概念引入主流软件开发。Fowler还著有《企业应用架构模式》、《UML精粹》,以及多篇关于软件设计、敏捷方法论和持续交付的有影响力的文章。他是敏捷宣言的签署者之一,数十年来一直倡导进化式设计——通过严谨的增量重构持续改进代码结构,而非进行前期的大型设计。他的重构目录最初以Java编写,现已被适配到几乎所有编程语言,并内置到各大IDE的自动重构工具中。