refactoring-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Refactoring Patterns: Operations & Techniques

重构模式:操作与技巧

A focused guide to the seven most impactful refactoring operations. Unlike code bloaters (which are smells to avoid), these are techniques you actively apply to improve design, clarity, and maintainability.

这是一份聚焦7种最高效重构操作的指南。与需要避免的代码膨胀(code bloaters,属于代码异味)不同,这些是你可以主动应用来提升代码设计、清晰度和可维护性的技术

Pattern #1: Extract Method / Extract Function

模式1:提取方法/提取函数

What It Is

定义

Pull out a section of code into a separate, named method/function. This is the most frequent refactoring operation.
将一段代码抽取到独立的、有明确命名的方法/函数中,这是最常用的重构操作。

When to Use

适用场景

  • Code section has a clear, single purpose but is buried in a larger method
  • Same logic appears in multiple places (extract once, reuse everywhere)
  • Method has complex local variables and you want to isolate them
  • You want to test a section in isolation
  • Code comment describes what a section does — that's a candidate for extraction
  • 代码段有清晰单一的职责,但嵌套在更大的方法中
  • 相同逻辑出现在多个位置(抽取一次,随处复用)
  • 方法包含复杂的局部变量,你希望将其隔离
  • 你希望单独测试某一段代码
  • 有代码注释说明某段代码的作用——这就是抽取的候选对象

Detection Pattern

问题代码示例

typescript
// ❌ Logic buried in larger method
function processOrder(order: Order) {
  // ... 20 lines of setup ...

  // Validate payment
  if (order.payment.amount <= 0) {
    throw new Error("Amount must be positive");
  }
  if (!order.payment.cardToken) {
    throw new Error("Card required");
  }
  if (order.payment.amount > order.payment.cardLimit) {
    throw new Error("Exceeds card limit");
  }

  // ... 20 more lines ...
}
typescript
// ❌ 逻辑嵌套在大型方法中
function processOrder(order: Order) {
  // ... 20行初始化代码 ...

  // Validate payment
  if (order.payment.amount <= 0) {
    throw new Error("Amount must be positive");
  }
  if (!order.payment.cardToken) {
    throw new Error("Card required");
  }
  if (order.payment.amount > order.payment.cardLimit) {
    throw new Error("Exceeds card limit");
  }

  // ... 另外20行代码 ...
}

Refactoring: Extract Method

重构方案:提取方法

typescript
// ✅ Validation isolated and reusable
function processOrder(order: Order) {
  // ... setup ...
  validatePayment(order.payment);
  // ... rest of logic ...
}

function validatePayment(payment: Payment) {
  if (payment.amount <= 0) {
    throw new Error("Amount must be positive");
  }
  if (!payment.cardToken) {
    throw new Error("Card required");
  }
  if (payment.amount > payment.cardLimit) {
    throw new Error("Exceeds card limit");
  }
}
Payoff: Each method is shorter, intent is clearer, validation can be tested and reused, easier to change validation logic in one place.

typescript
// ✅ 校验逻辑被隔离且可复用
function processOrder(order: Order) {
  // ... 初始化代码 ...
  validatePayment(order.payment);
  // ... 剩余逻辑 ...
}

function validatePayment(payment: Payment) {
  if (payment.amount <= 0) {
    throw new Error("Amount must be positive");
  }
  if (!payment.cardToken) {
    throw new Error("Card required");
  }
  if (payment.amount > payment.cardLimit) {
    throw new Error("Exceeds card limit");
  }
}
收益: 每个方法更简短,意图更清晰,校验逻辑可被测试和复用,修改校验逻辑时只需在一处调整。

Pattern #2: Extract Class

模式2:提取类

What It Is

定义

Move a group of related fields and methods into a separate class. This splits responsibilities and makes the original class simpler.
将一组相关的字段和方法移动到独立的类中,拆分职责,让原类更简洁。

When to Use

适用场景

  • Class has too many responsibilities (multiple reasons to change)
  • A subset of fields are only used together in certain methods
  • You find yourself passing the same group of parameters repeatedly
  • Class is hard to instantiate or test due to complexity
  • 类承担了过多职责(有多个变更原因)
  • 某一部分字段仅在特定方法中配套使用
  • 你发现自己反复传递同一组参数
  • 类过于复杂,难以实例化或测试

Detection Pattern

问题代码示例

typescript
// ❌ Mixed concerns in one class
class Order {
  id: string;
  customerId: string;
  items: OrderItem[];

  // Address fields scattered
  shippingStreet: string;
  shippingCity: string;
  shippingZip: string;
  billingStreet: string;
  billingCity: string;
  billingZip: string;

  getShippingAddress(): string { /* ... */ }
  getBillingAddress(): string { /* ... */ }
  updateShippingAddress(street, city, zip) { /* ... */ }
  validateShippingAddress() { /* ... */ }
  calculateShippingCost() { /* ... */ }
}
typescript
// ❌ 单个类混杂了多个职责
class Order {
  id: string;
  customerId: string;
  items: OrderItem[];

  // 地址字段分散
  shippingStreet: string;
  shippingCity: string;
  shippingZip: string;
  billingStreet: string;
  billingCity: string;
  billingZip: string;

  getShippingAddress(): string { /* ... */ }
  getBillingAddress(): string { /* ... */ }
  updateShippingAddress(street, city, zip) { /* ... */ }
  validateShippingAddress() { /* ... */ }
  calculateShippingCost() { /* ... */ }
}

Refactoring: Extract Class

重构方案:提取类

typescript
// ✅ Address responsibility extracted
class Address {
  street: string;
  city: string;
  zip: string;

  validate(): void { /* ... */ }
  toString(): string { /* ... */ }
}

class Order {
  id: string;
  customerId: string;
  items: OrderItem[];
  shippingAddress: Address;
  billingAddress: Address;

  calculateShippingCost(): void { /* ... */ }
}
Payoff: Each class is focused, easier to test, Address is reusable in other contexts, dependencies are clear.

typescript
// ✅ 地址相关职责被抽取出来
class Address {
  street: string;
  city: string;
  zip: string;

  validate(): void { /* ... */ }
  toString(): string { /* ... */ }
}

class Order {
  id: string;
  customerId: string;
  items: OrderItem[];
  shippingAddress: Address;
  billingAddress: Address;

  calculateShippingCost(): void { /* ... */ }
}
收益: 每个类职责聚焦,更易测试,Address类可在其他场景复用,依赖关系更清晰。

Pattern #3: Replace Conditional with Polymorphism

模式3:用多态替换条件判断

What It Is

定义

Replace if/switch statements that check object type with polymorphic method calls. The type determines which implementation runs.
将检查对象类型的if/switch语句替换为多态方法调用,由对象类型决定运行哪一个实现。

When to Use

适用场景

  • Multiple if/switch statements checking the same type or status
  • Different behavior based on object type (animal.type === 'dog')
  • Same logic repeated for different cases
  • Adding a new type requires changing multiple places (violates Open/Closed Principle)
  • 多个if/switch语句检查相同的类型或状态
  • 行为根据对象类型不同而变化(例如animal.type === 'dog')
  • 相同逻辑在不同分支重复出现
  • 新增类型需要修改多处代码(违反开闭原则)

Detection Pattern

问题代码示例

typescript
// ❌ Type-based conditionals scattered
function calculateDiscount(customer: Customer): number {
  if (customer.type === "gold") {
    return customer.totalSpent * 0.15;
  } else if (customer.type === "silver") {
    return customer.totalSpent * 0.10;
  } else if (customer.type === "bronze") {
    return customer.totalSpent * 0.05;
  }
  return 0;
}

function sendNotification(customer: Customer, message: string) {
  if (customer.type === "gold") {
    sendEmail(customer.email, message);
    sendSMS(customer.phone, message);
  } else if (customer.type === "silver") {
    sendEmail(customer.email, message);
  } else {
    // bronze gets nothing
  }
}
typescript
// ❌ 基于类型的条件判断分散在各处
function calculateDiscount(customer: Customer): number {
  if (customer.type === "gold") {
    return customer.totalSpent * 0.15;
  } else if (customer.type === "silver") {
    return customer.totalSpent * 0.10;
  } else if (customer.type === "bronze") {
    return customer.totalSpent * 0.05;
  }
  return 0;
}

function sendNotification(customer: Customer, message: string) {
  if (customer.type === "gold") {
    sendEmail(customer.email, message);
    sendSMS(customer.phone, message);
  } else if (customer.type === "silver") {
    sendEmail(customer.email, message);
  } else {
    // bronze等级用户不接收通知
  }
}

Refactoring: Use Polymorphism

重构方案:使用多态

typescript
// ✅ Each customer type knows its own behavior
interface Customer {
  name: string;
  totalSpent: number;
  calculateDiscount(): number;
  sendNotification(message: string): void;
}

class GoldCustomer implements Customer {
  calculateDiscount(): number {
    return this.totalSpent * 0.15;
  }

  sendNotification(message: string): void {
    sendEmail(this.email, message);
    sendSMS(this.phone, message);
  }
}

class SilverCustomer implements Customer {
  calculateDiscount(): number {
    return this.totalSpent * 0.10;
  }

  sendNotification(message: string): void {
    sendEmail(this.email, message);
  }
}

class BronzeCustomer implements Customer {
  calculateDiscount(): number {
    return this.totalSpent * 0.05;
  }

  sendNotification(message: string): void {
    // intentionally does nothing
  }
}

// Call site is now simple
const discount = customer.calculateDiscount();
customer.sendNotification(msg);
Payoff: Adding a new customer type is just a new class, no existing code changes, behavior is localized, easier to test each type in isolation, follows Open/Closed Principle.

typescript
// ✅ 每个客户类型管理自己的行为
interface Customer {
  name: string;
  totalSpent: number;
  calculateDiscount(): number;
  sendNotification(message: string): void;
}

class GoldCustomer implements Customer {
  calculateDiscount(): number {
    return this.totalSpent * 0.15;
  }

  sendNotification(message: string): void {
    sendEmail(this.email, message);
    sendSMS(this.phone, message);
  }
}

class SilverCustomer implements Customer {
  calculateDiscount(): number {
    return this.totalSpent * 0.10;
  }

  sendNotification(message: string): void {
    sendEmail(this.email, message);
  }
}

class BronzeCustomer implements Customer {
  calculateDiscount(): number {
    return this.totalSpent * 0.05;
  }

  sendNotification(message: string): void {
    //  intentionally does nothing
  }
}

// 调用处现在非常简洁
const discount = customer.calculateDiscount();
customer.sendNotification(msg);
收益: 新增客户类型只需要新增一个类,无需修改现有代码,行为本地化,更容易单独测试每个类型,符合开闭原则。

Pattern #4: Introduce Variable / Extract Variable

模式4:引入变量/提取变量

What It Is

定义

Assign an intermediate result or complex expression to a named variable. This makes intent clearer and breaks up nested logic.
将中间结果或复杂表达式赋值给一个有命名的变量,让意图更清晰,拆分嵌套逻辑。

When to Use

适用场景

  • Complex expression is hard to read at first glance
  • Same complex expression appears multiple times
  • You want to give a semantic name to an intermediate result
  • Expression uses multiple operators and precedence is confusing
  • 复杂表达式第一眼难以理解
  • 相同的复杂表达式出现多次
  • 你希望给中间结果一个语义化的名称
  • 表达式使用多个运算符,优先级容易混淆

Detection Pattern

问题代码示例

python
undefined
python
undefined

❌ Hard to parse

❌ 难以理解

if user.age >= 18 and user.country in ["US", "CA", "MX"] and
user.verification_status == "verified" and user.account_age_days > 30: allow_checkout()
undefined
if user.age >= 18 and user.country in ["US", "CA", "MX"] and
user.verification_status == "verified" and user.account_age_days > 30: allow_checkout()
undefined

Refactoring: Introduce Variable

重构方案:引入变量

python
undefined
python
undefined

✅ Clear intent

✅ 意图清晰

is_adult = user.age >= 18 is_allowed_region = user.country in ["US", "CA", "MX"] is_verified = user.verification_status == "verified" is_established = user.account_age_days > 30
if is_adult and is_allowed_region and is_verified and is_established: allow_checkout()
is_adult = user.age >= 18 is_allowed_region = user.country in ["US", "CA", "MX"] is_verified = user.verification_status == "verified" is_established = user.account_age_days > 30
if is_adult and is_allowed_region and is_verified and is_established: allow_checkout()

Even better: extract to a method

更优方案:抽取为方法

def is_eligible_for_checkout(user: User) -> bool: return ( user.age >= 18 and user.country in ["US", "CA", "MX"] and user.verification_status == "verified" and user.account_age_days > 30 )
if is_eligible_for_checkout(user): allow_checkout()

**Payoff:** Readability improves, intent is explicit, logic can be tested separately, same condition can be reused.

---
def is_eligible_for_checkout(user: User) -> bool: return ( user.age >= 18 and user.country in ["US", "CA", "MX"] and user.verification_status == "verified" and user.account_age_days > 30 )
if is_eligible_for_checkout(user): allow_checkout()

**收益:** 可读性提升,意图明确,逻辑可单独测试,相同判断可复用。

---

Pattern #5: Simplify Conditional Logic

模式5:简化条件逻辑

What It Is

定义

Reduce nested if/else statements, remove duplication in conditions, or flatten logic flow. Common strategies: consolidate conditions, use guard clauses, remove unnecessary nesting.
减少嵌套的if/else语句,移除条件中的重复逻辑,扁平化逻辑流。常见策略:合并条件、使用卫语句、移除不必要的嵌套。

When to Use

适用场景

  • Multiple if/else branches doing similar things
  • Deep nesting (3+ levels)
  • Repeated condition checks
  • Method has many early exits that aren't guard clauses
  • Boolean flags are being set and checked repeatedly
  • 多个if/else分支做相似的事情
  • 深度嵌套(3层及以上)
  • 重复的条件检查
  • 方法有很多非卫语句的提前退出
  • 反复设置和检查布尔标志

Detection Pattern: Guard Clauses

问题代码示例:卫语句场景

typescript
// ❌ Nested if/else (default case buried at end)
function calculateShipping(order: Order): ShippingCost {
  if (order.weight > 0) {
    if (order.destination !== null) {
      if (order.isPriority) {
        return calculateExpressShipping(order);
      } else {
        return calculateStandardShipping(order);
      }
    } else {
      throw new Error("No destination");
    }
  } else {
    throw new Error("Invalid weight");
  }
}
typescript
// ❌ 嵌套if/else(默认逻辑藏在末尾)
function calculateShipping(order: Order): ShippingCost {
  if (order.weight > 0) {
    if (order.destination !== null) {
      if (order.isPriority) {
        return calculateExpressShipping(order);
      } else {
        return calculateStandardShipping(order);
      }
    } else {
      throw new Error("No destination");
    }
  } else {
    throw new Error("Invalid weight");
  }
}

Refactoring: Guard Clauses (fail fast)

重构方案:卫语句(快速失败)

typescript
// ✅ Guards at top, happy path clear
function calculateShipping(order: Order): ShippingCost {
  if (order.weight <= 0) {
    throw new Error("Invalid weight");
  }
  if (!order.destination) {
    throw new Error("No destination");
  }

  if (order.isPriority) {
    return calculateExpressShipping(order);
  }
  return calculateStandardShipping(order);
}
Payoff: Logic is easier to follow (top to bottom), invalid cases fail immediately, happy path is obvious, fewer nested levels.

typescript
// ✅ 卫语句放在顶部,主流程清晰
function calculateShipping(order: Order): ShippingCost {
  if (order.weight <= 0) {
    throw new Error("Invalid weight");
  }
  if (!order.destination) {
    throw new Error("No destination");
  }

  if (order.isPriority) {
    return calculateExpressShipping(order);
  }
  return calculateStandardShipping(order);
}
收益: 逻辑从上到下更容易理解,非法场景快速报错,主流程一目了然,嵌套层级更少。

Pattern #6: Move Method / Move Field

模式6:移动方法/移动字段

What It Is

定义

Relocate a method or field to a class where it's more closely related or more frequently used. Reduces coupling.
将方法或字段移动到与其关联更紧密、使用更频繁的类中,降低耦合。

When to Use

适用场景

  • Method uses more data from another class than its own
  • Method is called more often from another class
  • Field is only used in one method and belongs with related data
  • You're refactoring toward better cohesion
  • 方法使用其他类的数据比自身类更多
  • 方法被其他类调用的频率更高
  • 字段仅在一个方法中使用,应该和相关数据放在一起
  • 你正在重构以提升内聚性

Detection Pattern

问题代码示例

typescript
// ❌ Method belongs elsewhere
class Order {
  items: OrderItem[];
  customer: Customer;

  // This method uses mostly customer data
  calculateCustomerDiscount(): number {
    if (this.customer.isPremium) {
      return this.items.reduce((sum, item) => sum + item.price, 0) * 0.15;
    }
    return 0;
  }
}
typescript
// ❌ 方法所属类不对
class Order {
  items: OrderItem[];
  customer: Customer;

  // 该方法主要使用客户数据
  calculateCustomerDiscount(): number {
    if (this.customer.isPremium) {
      return this.items.reduce((sum, item) => sum + item.price, 0) * 0.15;
    }
    return 0;
  }
}

Refactoring: Move to Customer

重构方案:移动到Customer类

typescript
// ✅ Discount logic lives with customer
class Customer {
  isPremium: boolean;

  calculateDiscount(orderTotal: number): number {
    return this.isPremium ? orderTotal * 0.15 : 0;
  }
}

class Order {
  items: OrderItem[];
  customer: Customer;

  getTotal(): number {
    const subtotal = this.items.reduce((sum, item) => sum + item.price, 0);
    const discount = this.customer.calculateDiscount(subtotal);
    return subtotal - discount;
  }
}
Payoff: Related data lives together, less coupling, method is reusable in other contexts, responsibilities are clearer.

typescript
// ✅ 折扣逻辑和客户数据放在一起
class Customer {
  isPremium: boolean;

  calculateDiscount(orderTotal: number): number {
    return this.isPremium ? orderTotal * 0.15 : 0;
  }
}

class Order {
  items: OrderItem[];
  customer: Customer;

  getTotal(): number {
    const subtotal = this.items.reduce((sum, item) => sum + item.price, 0);
    const discount = this.customer.calculateDiscount(subtotal);
    return subtotal - discount;
  }
}
收益: 相关数据放在一起,耦合度更低,方法可在其他场景复用,职责更清晰。

Pattern #7: Rename (Variable, Method, Class)

模式7:重命名(变量、方法、类)

What It Is

定义

Give something a clearer, more intention-revealing name. This is often the most underrated refactoring.
给元素一个更清晰、更能体现意图的名称,这通常是最被低估的重构操作。

When to Use

适用场景

  • Name doesn't express intent (e.g.,
    calc
    ,
    tmp
    ,
    data
    )
  • Name is misleading or outdated
  • Name requires explanation (code comment says what it does)
  • Single letter or abbreviation obscures meaning
  • 名称不能表达意图(例如
    calc
    tmp
    data
  • 名称有误导性或已经过时
  • 名称需要额外解释(靠代码注释说明作用)
  • 单字母或缩写掩盖了实际含义

Detection Pattern

问题代码示例

typescript
// ❌ Poor naming requires mental mapping
function proc(d: any[]): any[] {
  const r = [];
  for (let i = 0; i < d.length; i++) {
    if (d[i].s === "active") {
      r.push(d[i].amt * 1.15); // What's being calculated?
    }
  }
  return r;
}
typescript
// ❌ 糟糕的命名需要额外的心智映射
function proc(d: any[]): any[] {
  const r = [];
  for (let i = 0; i < d.length; i++) {
    if (d[i].s === "active") {
      r.push(d[i].amt * 1.15); // 这里在计算什么?
    }
  }
  return r;
}

Refactoring: Clearer Names

重构方案:更清晰的命名

typescript
// ✅ Intent is self-evident
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
  const taxAdjustedAmounts = [];
  for (const order of orders) {
    if (order.status === "active") {
      const taxRate = 1.15; // 15% tax
      taxAdjustedAmounts.push(order.amount * taxRate);
    }
  }
  return taxAdjustedAmounts;
}

// Even better with functional approach
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
  return orders
    .filter((order) => order.status === "active")
    .map((order) => order.amount * 1.15);
}
Payoff: Code is self-documenting, onboarding is faster, fewer bugs from misunderstanding, refactoring opportunities become obvious.

typescript
// ✅ 意图不言自明
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
  const taxAdjustedAmounts = [];
  for (const order of orders) {
    if (order.status === "active") {
      const taxRate = 1.15; // 15% tax
      taxAdjustedAmounts.push(order.amount * taxRate);
    }
  }
  return taxAdjustedAmounts;
}

// 用函数式写法更优
function calculateTaxAdjustedAmounts(orders: Order[]): number[] {
  return orders
    .filter((order) => order.status === "active")
    .map((order) => order.amount * 1.15);
}
收益: 代码自解释,新人上手更快,因理解错误导致的Bug更少,重构机会更明显。

Quick Reference: When to Use Each Pattern

快速参考:各模式适用场景

PatternUse WhenPayoff
Extract MethodLogic has single purpose, appears multiple times, or is hard to testReusable, testable, clearer intent
Extract ClassClass has multiple responsibilities or mixed concernsFocused, reusable, easier to test
Replace ConditionalSame type/status check scattered in multiple placesOpen/Closed Principle, localized behavior, extensible
Introduce VariableComplex expression is hard to read or repeatedSelf-documenting, testable, reusable
Simplify ConditionalNested or complex if/else logicReadable, fail-fast, happy path clear
Move Method/FieldMethod/field belongs logically elsewhereBetter cohesion, less coupling, reusable
RenameName doesn't express intentSelf-documenting, faster onboarding, clearer design

模式适用场景收益
提取方法逻辑有单一职责、多次出现、难以单独测试可复用、可测试、意图更清晰
提取类类有多个职责或混杂了不同关注点职责聚焦、可复用、更易测试
替换条件判断相同的类型/状态检查分散在多个位置符合开闭原则、行为本地化、可扩展
引入变量复杂表达式难以阅读或重复出现自解释、可测试、可复用
简化条件判断嵌套或复杂的if/else逻辑可读性高、快速失败、主流程清晰
移动方法/字段方法/字段逻辑上属于其他类内聚性更高、耦合度更低、可复用
重命名名称不能表达实际意图代码自解释、上手更快、设计更清晰

Code Review Workflow

代码评审工作流

When reviewing code for refactoring opportunities:
  1. Extract Method — Look for inline comments describing logic sections
  2. Extract Class — Spot multiple reasons to change the class or scattered concerns
  3. Replace Conditional — Find type/status checks repeated across methods
  4. Introduce Variable — Find complex expressions or repeated conditions
  5. Simplify Conditional — Count nesting levels (>2 is suspicious) and guard clauses
  6. Move Method — Check what data/methods the method actually uses
  7. Rename — Ask "Is this name self-documenting?" for every significant identifier
For each opportunity found:
  • Identify the pattern
  • Explain the current problem (readability, coupling, testability)
  • Show the refactoring with a concrete before/after
  • Explain the payoff

评审代码寻找重构机会时,按以下步骤检查:
  1. 提取方法 — 寻找描述逻辑段的行内注释
  2. 提取类 — 识别类有多个变更原因或分散的关注点
  3. 替换条件判断 — 查找跨方法重复出现的类型/状态检查
  4. 引入变量 — 查找复杂表达式或重复的判断条件
  5. 简化条件判断 — 统计嵌套层级(超过2层就需要注意)和卫语句
  6. 移动方法 — 检查方法实际使用的数据/方法属于哪个类
  7. 重命名 — 对每个重要的标识符询问:「这个名称是自解释的吗?」
发现每个重构机会时:
  • 识别对应的重构模式
  • 说明当前的问题(可读性、耦合度、可测试性)
  • 给出修改前后的具体示例
  • 说明重构的收益

References

参考资料

  • Source: Martin Fowler's Refactoring Catalog — 72+ techniques organized by operation
  • Complementary: See
    refactoring-catalog
    skill for code bloater smells (things to avoid)
  • Principles: Single Responsibility, Open/Closed, DRY (Don't Repeat Yourself)
  • 来源: Martin Fowler的重构目录 — 收录72种以上按操作分类的重构技巧
  • 补充内容: 查看
    refactoring-catalog
    技能了解需要避免的代码膨胀异味
  • 相关原则: 单一职责原则、开闭原则、DRY(不要重复自己)原则