refactor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Refactor — Expert Code Restructuring

代码重构——专业代码重组

Surgical code refactoring based on Martin Fowler's <Refactoring> (2nd Edition) catalog. Improve structure, readability, and maintainability without changing external behavior. Gradual evolution, not revolution.

基于Martin Fowler《Refactoring》(第二版)目录的精准代码重构。在不改变外部行为的前提下,提升代码结构、可读性和可维护性。采用渐进式演进,而非彻底重写。

When to Use

适用场景

This skill activates when:
  • Code is hard to understand or maintain
  • Functions/classes have grown too large
  • Code smells are detected
  • Adding features is difficult due to poor structure
  • User explicitly requests refactoring, cleanup, or improvement
  • User says: refactor, 重构, clean up, improve code, code smell, extract method, rename, simplify

当出现以下情况时,该技能会激活:
  • 代码难以理解或维护
  • 函数/类过于庞大
  • 检测到代码坏味道
  • 因结构不佳导致新增特性困难
  • 用户明确要求重构、清理或优化代码
  • 用户提及:refactor、重构、clean up、improve code、code smell、extract method、rename、simplify

The Golden Rules

黄金准则

These five rules are non-negotiable. Violating any of them turns refactoring into reckless editing.
以下五条准则不容违背。违反任何一条都会让重构变成鲁莽的代码编辑。

1. Behavior is Preserved

1. 保留原有行为

Only how the code works changes, never what it does. If tests existed before, they must pass after. If the refactoring introduces a behavioral change, it's not refactoring — it's rewriting.
仅改变代码的运行方式,绝不改变其功能。如果重构前已有测试用例,重构后必须全部通过。若重构引入了行为变更,那这不是重构——而是重写。

2. Small Steps

2. 小步迭代

Each change should be the smallest possible transformation that compiles and passes tests. If a step breaks, you know exactly which change caused it. Refactoring is a series of tiny, safe transformations, not one big rewrite.
每次变更都应是最小的可编译且通过测试的转换。如果某一步出错,你能准确知道是哪次变更导致的。重构是一系列微小、安全的转换,而非一次大规模重写。

3. Version Control is Your Friend

3. 版本控制是你的好帮手

Commit before starting. Commit after each successful step. This gives you infinite undo. Branch from a clean state so you can abandon the refactoring without consequences.
开始前提交代码。每完成一步成功的转换后提交代码。这能让你无限次回退。从干净的状态创建分支,这样即使放弃重构也不会造成影响。

4. Tests are Essential

4. 测试必不可少

"Without tests, you're not refactoring — you're just editing." If tests don't exist for the target code, write characterization tests first. These tests capture the current behavior so you can detect regressions.
“没有测试,你不是在重构——只是在编辑代码。”如果目标代码没有测试用例,先编写特征测试。这类测试会捕获当前行为,以便你检测回归问题。

5. One Thing at a Time

5. 一次只做一件事

Never mix refactoring with feature changes. Never refactor two unrelated things simultaneously. Each commit should contain exactly one refactoring operation.

永远不要将重构与特性变更混在一起。永远不要同时重构两个不相关的内容。每次提交应只包含一项重构操作。

When NOT to Refactor

不适宜重构的场景

ScenarioAction
Code works and won't change againLeave it alone
Critical production path with no testsWrite characterization tests first
Under tight deadline pressureDocument the smell, refactor later
No clear purpose or benefitDon't refactor for refactoring's sake
Code is fundamentally wrongThis is a rewrite, not a refactoring

场景应对措施
代码正常运行且不会再变更保持原样
关键生产路径无测试用例先编写特征测试
面临紧迫的截止日期记录代码坏味道,后续再重构
无明确目的或收益不要为了重构而重构
代码存在根本性错误这属于重写,而非重构

Code Smells Catalog

代码坏味道目录

Based on Fowler's taxonomy. Before refactoring, identify which smell is present.
基于Fowler的分类体系。重构前,先识别存在的坏味道类型。

Bloaters

臃肿类

SmellDescriptionPrimary Refactoring
Long MethodMethod > 10-15 lines, doing multiple thingsExtract Method, Replace Temp with Query
Large ClassClass with too many fields/methods (God Object)Extract Class, Extract Subclass
Primitive ObsessionUsing primitives instead of small objectsReplace Data Value with Object, Replace Type Code with Class
Long Parameter ListMethod with > 3-4 parametersIntroduce Parameter Object, Preserve Whole Object
Data ClumpsSame group of data appearing togetherExtract Class, Introduce Parameter Object
坏味道描述主要重构手法
Long Method方法超过10-15行,承担多项职责Extract Method、Replace Temp with Query
Large Class包含过多字段/方法的类(上帝对象)Extract Class、Extract Subclass
Primitive Obsession使用基本类型而非小型对象Replace Data Value with Object、Replace Type Code with Class
Long Parameter List方法参数超过3-4个Introduce Parameter Object、Preserve Whole Object
Data Clumps同一组数据重复出现Extract Class、Introduce Parameter Object

Object-Orientation Abusers

面向对象滥用

SmellDescriptionPrimary Refactoring
Switch StatementsRepeated switch/if-else on type codesReplace Conditional with Polymorphism, Replace Type Code with Subclasses
Temporary FieldField only set in certain circumstancesExtract Class, Introduce Null Object
Refused BequestSubclass doesn't use inherited membersReplace Inheritance with Delegation, Push Down Method/Field
Alternative Classes with Different InterfacesClasses doing similar things with different namesRename Method, Move Method, Extract Superclass
坏味道描述主要重构手法
Switch Statements重复基于类型码的switch/if-else语句Replace Conditional with Polymorphism、Replace Type Code with Subclasses
Temporary Field仅在特定场景下被赋值的字段Extract Class、Introduce Null Object
Refused Bequest子类未使用继承的成员Replace Inheritance with Delegation、Push Down Method/Field
Alternative Classes with Different Interfaces功能相似但接口不同的类Rename Method、Move Method、Extract Superclass

Change Preventers

变更阻碍

SmellDescriptionPrimary Refactoring
Divergent ChangeOne class changed for different reasonsExtract Class
Shotgun SurgeryOne change requires many small changes across classesMove Method, Move Field, Inline Class
Parallel Inheritance HierarchiesAdding a subclass to one hierarchy forces adding to anotherMove Method, Move Field
坏味道描述主要重构手法
Divergent Change一个类因不同原因被修改Extract Class
Shotgun Surgery一项变更需要在多个类中进行多处小修改Move Method、Move Field、Inline Class
Parallel Inheritance Hierarchies在一个层级中添加子类会强制在另一个层级也添加子类Move Method、Move Field

Dispensables

冗余代码

SmellDescriptionPrimary Refactoring
CommentsComments explaining what code does (not why)Extract Method, Rename Variable, Introduce Assertion
Duplicate CodeSame code structure in multiple placesExtract Method, Pull Up Method, Form Template Method
Lazy ClassClass doing too little to justify existenceInline Class, Collapse Hierarchy
Data ClassClass with only fields and getters/settersMove Method, Encapsulate Field, Encapsulate Collection
Dead CodeUnused code, imports, commented-out blocksDelete it (git history has it)
Speculative GeneralityCode built for "someday" that never cameInline Class, Collapse Hierarchy, Remove Parameter
坏味道描述主要重构手法
Comments解释代码功能(而非原因)的注释Extract Method、Rename Variable、Introduce Assertion
Duplicate Code多个位置存在相同代码结构Extract Method、Pull Up Method、Form Template Method
Lazy Class职责过少、无存在必要的类Inline Class、Collapse Hierarchy
Data Class仅包含字段和getter/setter的类Move Method、Encapsulate Field、Encapsulate Collection
Dead Code未使用的代码、导入语句、注释掉的代码块删除(git历史中会保留)
Speculative Generality为“未来可能用到”而编写但从未使用的代码Inline Class、Collapse Hierarchy、Remove Parameter

Couplers

耦合类

SmellDescriptionPrimary Refactoring
Feature EnvyMethod uses another class's data more than its ownMove Method, Extract Method + Move Method
Inappropriate IntimacyClasses know too much about each other's internalsMove Method, Move Field, Replace Delegation with Hidden Delegate
Message Chains
a.getB().getC().getD().doSomething()
Hide Delegate, Extract Method
Middle ManClass delegates everything to another classRemove Middle Man, Inline Method
Incomplete Library ClassLibrary missing methods you needIntroduce Foreign Method, Introduce Local Extension

坏味道描述主要重构手法
Feature Envy方法使用其他类的数据多于自身类的数据Move Method、Extract Method + Move Method
Inappropriate Intimacy类之间过度了解彼此的内部实现Move Method、Move Field、Replace Delegation with Hidden Delegate
Message Chains
a.getB().getC().getD().doSomething()
Hide Delegate、Extract Method
Middle Man类将所有职责委托给另一个类Remove Middle Man、Inline Method
Incomplete Library Class库缺少你需要的方法Introduce Foreign Method、Introduce Local Extension

Refactoring Techniques Catalog

重构手法目录

Organized by category, from Fowler's catalog. Each technique includes its mechanical steps.
按类别整理,源自Fowler的目录。每种手法包含具体操作步骤。

Composing Methods

方法组合

Extract Method

Extract Method

Turn a code fragment into a method whose name explains its purpose.
Mechanics:
  1. Create a new method named after what the fragment does (not how)
  2. Copy the extracted code into the new method
  3. Identify local variables: read-only become parameters, modified become return values
  4. Pass parameters and handle return values
  5. Replace the original fragment with a call to the new method
  6. Test
Before:
java
void printOwing() {
    printBanner();
    // Print details
    System.out.println("name: " + _name);
    System.out.println("amount: " + getOutstanding());
}
After:
java
void printOwing() {
    printBanner();
    printDetails(getOutstanding());
}

void printDetails(double outstanding) {
    System.out.println("name: " + _name);
    System.out.println("amount: " + outstanding);
}
将代码片段转换为一个名称能解释其用途的方法。
操作步骤:
  1. 创建一个以片段用途命名的新方法(而非实现方式)
  2. 将提取的代码复制到新方法中
  3. 识别局部变量:只读变量作为参数,修改后的变量作为返回值
  4. 传递参数并处理返回值
  5. 用新方法的调用替换原代码片段
  6. 测试
重构前:
java
void printOwing() {
    printBanner();
    // Print details
    System.out.println("name: " + _name);
    System.out.println("amount: " + getOutstanding());
}
重构后:
java
void printOwing() {
    printBanner();
    printDetails(getOutstanding());
}

void printDetails(double outstanding) {
    System.out.println("name: " + _name);
    System.out.println("amount: " + outstanding);
}

Inline Method

Inline Method

Replace a method call with its body when the method body is as clear as the name.
Mechanics:
  1. Check the method is not polymorphic (no subclasses override it)
  2. Find all callers
  3. Replace each call with the method body
  4. Delete the method definition
  5. Test
当方法体和方法名称一样清晰时,用方法体替换方法调用。
操作步骤:
  1. 确认该方法不是多态方法(没有子类重写它)
  2. 找到所有调用者
  3. 将每个调用替换为方法体
  4. 删除方法定义
  5. 测试

Extract Variable

Extract Variable

Put the result of an expression (or part of it) in a self-explanatory variable.
Before:
java
if (platform.toUpperCase().indexOf("MAC") > -1 &&
    browser.toUpperCase().indexOf("IE") > -1 &&
    wasInitialized() && resize > 0) {
    // ...
}
After:
java
final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;
if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
    // ...
}
将表达式(或其一部分)的结果赋值给一个自解释的变量。
重构前:
java
if (platform.toUpperCase().indexOf("MAC") > -1 &&
    browser.toUpperCase().indexOf("IE") > -1 &&
    wasInitialized() && resize > 0) {
    // ...
}
重构后:
java
final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;
if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
    // ...
}

Inline Temp

Inline Temp

Replace a temp variable with its expression when the temp is only used once and the expression is clear.
当临时变量仅被使用一次且表达式清晰时,用表达式替换临时变量。

Replace Temp with Query

Replace Temp with Query

Extract the expression into a method. Temps that are computed once and reused are replaced with method calls.
将表达式提取为方法。将计算一次并重复使用的临时变量替换为方法调用。

Split Temporary Variable

Split Temporary Variable

A temp assigned more than once (not loop/collecting) should be split into separate variables, one per responsibility.
被多次赋值(非循环/收集场景)的临时变量应拆分为多个变量,每个变量对应一项职责。

Remove Assignments to Parameters

Remove Assignments to Parameters

Don't assign to parameters. Use a local variable instead.
不要给参数赋值,改用局部变量。

Replace Method with Method Object

Replace Method with Method Object

When a long method uses many local variables that make Extract Method hard, turn the method into its own class, with locals as fields.
当长方法使用过多局部变量导致Extract Method难以实施时,将该方法转换为独立类,局部变量作为类的字段。

Substitute Algorithm

Substitute Algorithm

Replace an algorithm with a clearer one.

用更清晰的算法替换原有算法。

Moving Features Between Objects

对象间特性迁移

Move Method

Move Method

Move a method to the class where it's used most.
Mechanics:
  1. Check all features used by the method on its current class
  2. Check for polymorphism (subclass/superclass methods)
  3. Create the method on the target class, adapting as needed
  4. Reference the target object from the source
  5. Turn the source method into a delegating method, or remove it
  6. Test
将方法迁移到使用它最多的类中。
操作步骤:
  1. 检查当前类中该方法使用的所有特性
  2. 检查是否存在多态(子类/父类方法)
  3. 在目标类中创建该方法并按需调整
  4. 在源类中引用目标对象
  5. 将源方法转换为委托方法,或直接删除
  6. 测试

Move Field

Move Field

Move a field to the class where it's used most.
将字段迁移到使用它最多的类中。

Extract Class

Extract Class

When a class does the work of two, split it. Create a new class and move relevant fields and methods.
当一个类承担了两个类的职责时,拆分它。创建一个新类并迁移相关字段和方法。

Inline Class

Inline Class

When a class does almost nothing, absorb it into the class that uses it most.
当一个类几乎没有职责时,将其合并到使用它最多的类中。

Hide Delegate

Hide Delegate

Create methods on the server to hide the delegate chain.
manager = person.getDepartment().getManager()
manager = person.getManager()
.
在服务类中创建方法以隐藏委托链。例如将
manager = person.getDepartment().getManager()
改为
manager = person.getManager()

Remove Middle Man

Remove Middle Man

When a class is doing too much delegation, call the delegate directly.
当一个类过度委托时,直接调用委托类。

Introduce Foreign Method

Introduce Foreign Method

When a server class needs an additional method but you can't modify it, create a method on the client with the server instance as the first argument.
当服务类需要额外方法但无法修改它时,在客户端类中创建一个以服务实例为第一个参数的方法。

Introduce Local Extension

Introduce Local Extension

When you need multiple foreign methods, create an extension class (subclass or wrapper).

当需要多个外部方法时,创建一个扩展类(子类或包装类)。

Organizing Data

数据组织

Self Encapsulate Field

Self Encapsulate Field

Access fields through getters and setters, even within the owning class.
即使在所属类内部,也通过getter和setter访问字段。

Replace Data Value with Object

Replace Data Value with Object

When a data item needs additional data or behavior, turn it into an object.
Before:
java
class Order {
    private String customer;  // Just a string
}
After:
java
class Order {
    private Customer customer;  // Rich object with name, address, credit rating
}
当数据项需要额外数据或行为时,将其转换为对象。
重构前:
java
class Order {
    private String customer;  // Just a string
}
重构后:
java
class Order {
    private Customer customer;  // 包含名称、地址、信用评级的富对象
}

Change Value to Reference

Change Value to Reference

When you need to share one instance of an object across multiple places.
当需要在多个地方共享同一个对象实例时使用。

Change Reference to Value

Change Reference to Value

When a reference object is small, immutable, and you want value semantics.
当引用对象很小、不可变且需要值语义时使用。

Replace Array with Object

Replace Array with Object

When an array holds heterogeneous data (
String[] row = new String[3]
— name, score, wins), replace with an object.
当数组存储异构数据时(例如
String[] row = new String[3]
——名称、分数、获胜次数),用对象替换数组。

Replace Magic Number with Symbolic Constant

Replace Magic Number with Symbolic Constant

Replace literal numbers/strings with named constants.
用命名常量替换字面量数字/字符串。

Encapsulate Field

Encapsulate Field

Make public fields private and provide accessors.
将公共字段设为私有并提供访问器。

Encapsulate Collection

Encapsulate Collection

Never return the raw collection. Return a read-only view and provide add/remove methods.
永远不要返回原始集合。返回只读视图并提供添加/删除方法。

Replace Type Code with Class

Replace Type Code with Class

Replace a numeric/string type code with a class that has meaningful behavior.
用具有有意义行为的类替换数值/字符串类型码。

Replace Type Code with Subclasses

Replace Type Code with Subclasses

When type code affects behavior, use polymorphism instead of conditionals.
当类型码影响行为时,用多态替代条件判断。

Replace Type Code with State/Strategy

Replace Type Code with State/Strategy

Similar to subclasses but uses composition when the type can change at runtime.
与子类方式类似,但当类型可在运行时变更时使用组合方式。

Replace Subclass with Fields

Replace Subclass with Fields

When subclasses vary only in constant data, replace them with fields on a single class.

当子类仅在常量数据上存在差异时,用单个类的字段替换子类。

Simplifying Conditional Expressions

条件表达式简化

Decompose Conditional

Decompose Conditional

Extract the condition, then-part, and else-part into separate methods.
Before:
java
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
    charge = quantity * _winterRate + _winterServiceCharge;
} else {
    charge = quantity * _summerRate;
}
After:
java
if (isSummer(date)) {
    charge = summerCharge(quantity);
} else {
    charge = winterCharge(quantity);
}
将条件、then分支和else分支提取为独立方法。
重构前:
java
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
    charge = quantity * _winterRate + _winterServiceCharge;
} else {
    charge = quantity * _summerRate;
}
重构后:
java
if (isSummer(date)) {
    charge = summerCharge(quantity);
} else {
    charge = winterCharge(quantity);
}

Consolidate Conditional Expression

Consolidate Conditional Expression

Combine multiple conditionals that have the same result.
合并多个结果相同的条件判断。

Consolidate Duplicate Conditional Fragments

Consolidate Duplicate Conditional Fragments

Move code that appears in every branch outside the conditional.
将所有分支中重复的代码移到条件判断外部。

Remove Control Flag

Remove Control Flag

Replace control flags with break, continue, or return.
用break、continue或return替换控制标志。

Replace Nested Conditional with Guard Clauses

Replace Nested Conditional with Guard Clauses

Use early returns for special cases instead of deep nesting.
Before (arrow code):
java
double getPayAmount() {
    double result;
    if (_isDead) {
        result = deadAmount();
    } else {
        if (_isSeparated) {
            result = separatedAmount();
        } else {
            if (_isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }
    return result;
}
After:
java
double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();
    return normalPayAmount();
}
对特殊情况使用提前返回,替代深层嵌套。
重构前(箭头代码):
java
double getPayAmount() {
    double result;
    if (_isDead) {
        result = deadAmount();
    } else {
        if (_isSeparated) {
            result = separatedAmount();
        } else {
            if (_isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }
    return result;
}
重构后:
java
double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();
    return normalPayAmount();
}

Replace Conditional with Polymorphism

Replace Conditional with Polymorphism

When a conditional chooses different behavior based on the type of an object, use subclasses.
当条件判断基于对象类型选择不同行为时,使用子类。

Introduce Null Object

Introduce Null Object

Replace null checks with a null object that provides default behavior.
用提供默认行为的空对象替换空值检查。

Introduce Assertion

Introduce Assertion

State assumptions explicitly with assertions.

用断言明确声明假设。

Making Method Calls Simpler

方法调用简化

Rename Method

Rename Method

The name should say what the method does. If you can't think of a good name, the method may have multiple responsibilities.
方法名称应说明其功能。如果你想不出合适的名称,说明该方法可能承担了多项职责。

Add Parameter / Remove Parameter

Add Parameter / Remove Parameter

Add parameters when a method needs more info. Remove parameters when the method can get the info another way.
当方法需要更多信息时添加参数。当方法可通过其他方式获取信息时移除参数。

Separate Query from Modifier

Separate Query from Modifier

A method should either return a value OR change state, never both.
方法应要么返回值,要么改变状态,不可两者兼具。

Parameterize Method

Parameterize Method

Several methods doing similar things with different values → one method with a parameter.
将多个功能相似但参数不同的方法合并为一个带参数的方法。

Replace Parameter with Explicit Methods

Replace Parameter with Explicit Methods

The inverse: when a parameter essentially selects different behavior, create separate methods.
反向操作:当参数本质上是选择不同行为时,创建独立方法。

Preserve Whole Object

Preserve Whole Object

Pass the whole object instead of pulling individual fields from it.
传递整个对象,而非从中提取单个字段。

Replace Parameter with Method

Replace Parameter with Method

When a parameter can be computed from data the object already has.
当参数可从对象已有数据计算得出时使用。

Introduce Parameter Object

Introduce Parameter Object

Group parameters that naturally go together into an object.
将自然关联的参数组合成一个对象。

Remove Setting Method

Remove Setting Method

Make a field immutable by removing its setter and setting it in the constructor.
通过移除setter并在构造函数中初始化字段,使字段不可变。

Hide Method

Hide Method

Make methods private when they're not used outside the class.
当方法未在类外部使用时,设为私有。

Replace Constructor with Factory Method

Replace Constructor with Factory Method

When you need more flexibility than a simple constructor call.
当需要比简单构造函数调用更多灵活性时使用。

Replace Error Code with Exception

Replace Error Code with Exception

Throw an exception instead of returning an error code.
抛出异常而非返回错误码。

Replace Exception with Test

Replace Exception with Test

Check the condition first instead of catching an exception.

先检查条件而非捕获异常。

Dealing with Generalization

泛化处理

Pull Up Field/Method/Constructor Body

Pull Up Field/Method/Constructor Body

Move identical fields/methods/constructor code from subclasses to superclass.
将子类中相同的字段/方法/构造函数代码移到父类。

Push Down Method/Field

Push Down Method/Field

Move behavior from superclass to only the subclasses that use it.
将父类中的行为移到仅使用它的子类中。

Extract Subclass

Extract Subclass

Create a subclass for a subset of features used in some instances.
为部分实例使用的特性子集创建子类。

Extract Superclass

Extract Superclass

Create a superclass for shared features of similar classes.
为相似类的共享特性创建父类。

Extract Interface

Extract Interface

Create an interface from a subset of a class's public methods.
从类的公共方法子集中创建接口。

Collapse Hierarchy

Collapse Hierarchy

Merge a superclass and subclass when they're not different enough.
当父类和子类差异不大时,合并它们。

Form Template Method

Form Template Method

Generalize an algorithm in the superclass, letting subclasses fill in the specifics.
在父类中提取通用算法框架,让子类填充具体细节。

Replace Inheritance with Delegation

Replace Inheritance with Delegation

When a subclass only uses part of the superclass, use composition instead.
当子类仅使用父类的部分功能时,用组合替代继承。

Replace Delegation with Inheritance

Replace Delegation with Inheritance

When a delegating class needs access to all of the delegate's behavior.

当委托类需要访问委托对象的所有行为时使用。

The Refactoring Process

重构流程

Phase 1: Prepare

阶段1:准备

  1. Write characterization tests if they don't exist. These capture current behavior — they don't need to be elegant, just comprehensive enough to catch regressions.
  2. Commit current state. Start from a clean working tree.
  3. Create a branch for the refactoring. Keep it separate from feature work.
  1. 编写特征测试(如果不存在)。这类测试捕获当前行为——不需要优雅,只需足够全面以检测回归问题。
  2. 提交当前状态。从干净的工作区开始。
  3. 创建分支用于重构。与功能开发分离。

Phase 2: Identify

阶段2:识别

  1. Smell the code. Use the smell catalog above to classify what's wrong.
  2. Understand the code. Read it thoroughly. You must understand what it does before changing it.
  3. Choose the right refactoring. Pick from the technique catalog. Know what the result looks like before you start.
  1. 识别代码坏味道。使用上述坏味道目录分类问题。
  2. 理解代码。彻底阅读代码。在修改前必须理解其功能。
  3. 选择合适的重构手法。从手法目录中挑选。开始前要明确预期结果。

Phase 3: Refactor (Small Steps)

阶段3:重构(小步迭代)

For each step:
  1. Make one small change. One refactoring technique at a time.
  2. Compile. The code should compile after every change.
  3. Run tests. All tests must pass. If they don't, you've changed behavior.
  4. Commit. Create a commit with a message like
    refactor: extract validateEmail method
    .
Repeat until the smell is resolved.
每一步操作:
  1. 做出一个小变更。一次使用一种重构手法。
  2. 编译。每次变更后代码必须能编译通过。
  3. 运行测试。所有测试必须通过。如果未通过,说明你改变了行为。
  4. 提交。提交信息格式如:
    refactor: extract validateEmail method
重复操作直到坏味道解决。

Phase 4: Verify

阶段4:验证

  1. All tests pass. Non-negotiable.
  2. Manual check. Briefly run the application or review the diff for unintended changes.
  3. Performance. Ensure no performance regression. Simple refactorings rarely cause them, but check.
  1. 所有测试通过。这是硬性要求。
  2. 手动检查。快速运行应用或查看差异,确认无意外变更。
  3. 性能检查。确保没有性能退化。简单重构很少导致性能问题,但仍需检查。

Phase 5: Clean Up

阶段5:清理

  1. Remove stale comments. If a refactoring made a comment obvious, delete the comment.
  2. Check for dead code. After refactorings, unused code may emerge.
  3. Final commit. Summarize the refactoring sequence.

  1. 移除过时注释。如果重构让注释变得多余,删除注释。
  2. 检查冗余代码。重构后可能出现未使用的代码。
  3. 最终提交。总结重构过程。

Refactoring Checklist

重构检查清单

Code Quality

代码质量

  • Functions are small (< 20 lines preferred, < 50 lines max)
  • Each function does one thing (single responsibility)
  • No duplicated code (DRY)
  • Names describe what, not how
  • No magic numbers or strings
  • Dead code removed
  • 函数体量小(推荐少于20行,最多不超过50行)
  • 每个函数只做一件事(单一职责)
  • 无重复代码(DRY原则)
  • 名称描述功能,而非实现方式
  • 无魔法数字或字符串
  • 已移除冗余代码

Structure

结构

  • Related code is grouped together
  • Module boundaries are clear
  • Dependencies flow in one direction (no cycles)
  • No circular dependencies
  • 相关代码分组存放
  • 模块边界清晰
  • 依赖单向流动(无循环)
  • 无循环依赖

Conditionals

条件判断

  • Guard clauses replace deep nesting
  • Complex conditions extracted to named methods
  • Polymorphism replaces type-switching conditionals
  • Null Object pattern where appropriate
  • 使用卫语句替代深层嵌套
  • 复杂条件已提取为命名方法
  • 用多态替代基于类型的分支判断
  • 合理使用Null Object模式

Type Safety (typed languages)

类型安全(强类型语言)

  • Types defined for all public APIs
  • No
    any
    usage without qualification
  • Nullable types explicitly marked
  • Type codes replaced with classes/enums
  • 所有公共API都定义了类型
  • 无无理由的
    any
    类型使用
  • 可空类型已明确标记
  • 类型码已替换为类/枚举

Testing

测试

  • Refactored code is tested
  • Edge cases are covered
  • All tests pass after each step
  • Characterization tests capture pre-refactoring behavior

  • 重构后的代码已测试
  • 覆盖了边缘情况
  • 每一步后所有测试都通过
  • 特征测试捕获了重构前的行为

Language-Specific Guidance

语言特定指导

Java

Java

  • Prefer
    final
    for locals that shouldn't change
  • Use IDE automated refactorings (Eclipse/IntelliJ) for mechanical steps
  • Leverage the type system: enums, records (Java 14+), sealed classes (Java 17+)
  • 对不应变更的局部变量优先使用
    final
  • 机械步骤使用IDE自动重构(Eclipse/IntelliJ)
  • 利用类型系统:枚举、records(Java 14+)、密封类(Java 17+)

JavaScript/TypeScript

JavaScript/TypeScript

  • Use destructuring to reduce parameter count
  • Prefer
    const
    over
    let
    for immutable bindings
  • Use TypeScript union types instead of type codes
  • Nullish coalescing (
    ??
    ) and optional chaining (
    ?.
    ) eliminate null-check noise
  • 使用解构减少参数数量
  • 对不可变绑定优先使用
    const
    而非
    let
  • 用TypeScript联合类型替代类型码
  • 空值合并运算符(
    ??
    )和可选链(
    ?.
    )消除空值检查冗余

Python

Python

  • Use type hints for documenting intent during refactoring
  • Use
    dataclasses
    to replace tuple/data-class patterns
  • Use
    @property
    to replace getters
  • Context managers for resource cleanup patterns
  • 重构期间使用类型提示记录意图
  • dataclasses
    替换元组/数据类模式
  • @property
    替换getter
  • 用上下文管理器处理资源清理模式

Go

Go

  • Small interfaces preferred: accept interfaces, return structs
  • Use named return values when they improve clarity
  • Table-driven tests pair well with refactoring
  • Avoid deep nesting with early returns
  • 偏好小型接口:接受接口,返回结构体
  • 当能提升清晰度时使用命名返回值
  • 表驱动测试与重构适配性好
  • 用提前返回避免深层嵌套

Rust

Rust

  • Use
    Result
    and
    Option
    instead of error codes and null
  • Pattern matching replaces if-else chains
  • From
    trait implementations clean up type conversions
  • Derive macros reduce boilerplate

  • Result
    Option
    替代错误码和空值
  • 用模式匹配替代if-else链
  • From
    trait实现简化类型转换
  • 派生宏减少样板代码

Common Refactoring Sequences

常见重构序列

Extract Method Sequence

Extract Method序列

  1. Create a new method named after intent
  2. Copy code fragment into new method
  3. Identify local variables → parameters / return values
  4. Call new method from original location
  5. Test
  1. 创建一个以意图命名的新方法
  2. 将代码片段复制到新方法
  3. 识别局部变量 → 参数/返回值
  4. 在原位置调用新方法
  5. 测试

Replace Conditional with Polymorphism Sequence

Replace Conditional with Polymorphism序列

  1. Create subclasses for each variant
  2. Create a factory method that returns the right subclass
  3. Move the conditional body to the appropriate subclass method
  4. Delete the conditional
  1. 为每个变体创建子类
  2. 创建返回对应子类的工厂方法
  3. 将条件判断体移到对应子类方法中
  4. 删除条件判断

Extract Class Sequence

Extract Class序列

  1. Identify a coherent subset of fields and methods
  2. Create a new class
  3. Create an instance from the old class
  4. Move fields and methods one at a time
  5. Update references in old class
  6. Test after each move
  1. 识别一组相关的字段和方法
  2. 创建新类
  3. 在旧类中创建新类的实例
  4. 逐个迁移字段和方法
  5. 更新旧类中的引用
  6. 每次迁移后测试

Inline Class Sequence

Inline Class序列

  1. Identify all callers of the target class
  2. Move all methods/fields to the absorbing class
  3. Redirect all references to the absorbing class
  4. Delete the empty class
  5. Test

  1. 识别目标类的所有调用者
  2. 将所有方法/字段移到合并类中
  3. 将所有引用重定向到合并类
  4. 删除空类
  5. 测试

Safety Protocol

安全规范

Before You Touch Anything

动手前准备

1. Characterization tests  →  capture what the code does now
2. Git commit              →  save a known-good state
3. Branch                  →  isolate refactoring from other work
1. 特征测试  →  捕获当前代码行为
2. Git提交              →  保存已知的良好状态
3. 创建分支                  →  将重构与其他工作隔离

Every Single Step

每一步操作

1. One change              →  one refactoring technique
2. Compile                 →  must compile clean
3. Tests                   →  every test must pass
4. Commit                  →  message: "refactor: <technique> <what>"
1. 单一变更              →  一次使用一种重构手法
2. 编译                 →  必须编译通过
3. 测试                   →  所有测试必须通过
4. 提交                  →  信息格式:"refactor: <手法> <内容>"

If Tests Break

若测试失败

1. Undo the last change
2. Understand what broke and why
3. Try a smaller step
4. If the test was wrong and behavior was correct, fix the test FIRST, then retry
1. 撤销最后一次变更
2. 理解失败原因
3. 尝试更小的步骤
4. 如果测试错误但行为正确,先修复测试,再重试

On Completion

完成后

1. Full test suite         →  all tests pass
2. Manual smoke test       →  quick sanity check
3. Self-review diff        →  catch unintended changes
4. Final commit            →  describe the overall transformation

1. 完整测试套件         →  所有测试通过
2. 手动冒烟测试       →  快速 sanity 检查
3. 自查代码差异        →  发现意外变更
4. 最终提交            →  描述整体转换过程

Design Patterns in Refactoring

重构中的设计模式

Strategy Pattern

策略模式

Replace a conditional that chooses an algorithm. Smell: Switch on type code with different behavior per branch. Technique: Replace Conditional with Polymorphism + Extract Method.
替换选择算法的条件判断。坏味道: 基于类型码的分支判断,每个分支行为不同。手法: Replace Conditional with Polymorphism + Extract Method。

Template Method

模板方法模式

Extract common algorithm skeleton to superclass, letting subclasses fill in the variants. Smell: Duplicate code with slight variations. Technique: Form Template Method.
将通用算法框架提取到父类,让子类填充变体。坏味道: 存在细微差异的重复代码。手法: Form Template Method。

State Pattern

状态模式

Replace a state-based conditional by extracting each state's behavior into a class. Smell: Switch on status field with behavior variation. Technique: Replace Type Code with State/Strategy.
通过将每个状态的行为提取到类中,替换基于状态的条件判断。坏味道: 基于状态字段的分支判断,行为随状态变化。手法: Replace Type Code with State/Strategy。

Composite Pattern

组合模式

Treat individual objects and groups uniformly. Smell: Client code has special handling for single vs. collection cases. Technique: Extract Interface + Create Composite.
统一处理单个对象和对象组。坏味道: 客户端代码对单个对象和集合有特殊处理。手法: Extract Interface + Create Composite。

Decorator Pattern

装饰器模式

Add behavior dynamically by wrapping objects. Smell: Conditional logic for optional behaviors. Technique: Extract Class + use composition.
通过包装对象动态添加行为。坏味道: 针对可选行为的条件逻辑。手法: Extract Class + 使用组合。

Null Object Pattern

空对象模式

Replace null checks with a default object. Smell: Repeated
if (x == null)
checks. Technique: Introduce Null Object.

用默认对象替换空值检查。坏味道: 重复的
if (x == null)
检查。手法: Introduce Null Object。

Edge Cases & Gotchas

边缘情况与注意事项

ScenarioHandling
No tests existWrite characterization tests first. Run the code with various inputs, capture outputs. These are your safety net.
Refactoring breaks a distant testFIRST understand why. Maybe the test relied on implementation detail. If so, fix the test to test behavior, not implementation. Then resume.
User wants behavior change + refactor togetherREFUSE. Do them separately. Refactor first to make the behavior change easy, commit, then change behavior.
Method is too complex to step throughUse Replace Method with Method Object. Turn the whole method into a class where each step can be extracted.
Refactoring across a large codebaseExtract a micro-service or module boundary first. Then refactor within the boundary. "There is a refactoring for everything except too many refactorings."
IDE automated refactoring availableUse it. Modern IDEs can safely rename, extract method, introduce variable, etc. Only do it manually when the IDE can't.
Undo needed
git stash
or
git reset --hard
back to last commit. Small commits make this painless.

场景处理方式
无测试用例先编写特征测试。用各种输入运行代码,捕获输出。这是你的安全保障。
重构破坏了远程测试首先理解原因。可能测试依赖于实现细节。如果是这样,先修复测试使其测试行为而非实现,再继续重构。
用户要求同时变更行为和重构拒绝。分开进行。先重构以便于行为变更,提交后再修改行为。
方法过于复杂无法逐步处理使用Replace Method with Method Object。将整个方法转换为类,每个步骤都可提取。
跨大型代码库重构先提取微服务或模块边界。然后在边界内重构。“除了过多重构之外,一切都有对应的重构手法。”
IDE支持自动重构使用它。现代IDE可安全地重命名、提取方法、引入变量等。仅当IDE无法处理时手动操作。
需要回退使用
git stash
git reset --hard
回到上一次提交。小提交让回退毫无痛苦。

Resources

参考资源

  • Martin Fowler, Refactoring: Improving the Design of Existing Code (2nd Edition, 2018)
  • refactoring.com — Fowler's online catalog
  • refactoring.guru — Illustrated refactoring patterns
  • Martin Fowler, Refactoring: Improving the Design of Existing Code (第二版, 2018)
  • refactoring.com — Fowler的在线目录
  • refactoring.guru — 带插图的重构模式