代码重构模式 code-refactoring-patterns

这个技能提供了一套完整的代码重构模式,用于系统化地改进代码的可维护性、性能和清晰度,同时确保功能不变。它涵盖了常见代码异味、重构技术和最佳实践,帮助开发者提升软件质量。关键词包括代码重构、软件工程、代码质量、重构模式、代码优化、测试驱动开发。

架构设计 0 次安装 0 次浏览 更新于 3/7/2026

名称: 代码重构模式 描述: 系统化重构代码的方法,用于提高可维护性、性能和清晰度,同时保持功能不变 许可证: MIT 元数据: 改编者: ai-skills 类别: 代码质量

代码重构模式

一个全面的指南,用于系统化地重构代码,同时保持功能并提高质量。

何时重构

  • 检测到代码异味(重复代码、长函数等)
  • 在向复杂区域添加新功能之前
  • 理解改进后(“现在我看到了更好的方法”)
  • 当测试就位时
  • 需要性能优化时

重构规则

  1. 永远不要在没有测试的情况下重构:如果测试不存在,先写测试
  2. 小步前进:一次只做一个更改
  3. 每次更改后运行测试:确保没有破坏任何东西
  4. 经常提交:每个工作重构都是一个提交
  5. 不要将重构与功能工作混在一起:分开关注点

常见代码异味

1. 长方法/函数

异味:函数超过20-30行

重构:提取方法

// 之前
function processOrder(order: Order) {
  // 验证订单 (10 lines)
  // 计算总计 (15 lines)
  // 应用折扣 (12 lines)
  // 发送确认 (8 lines)
}

// 之后
function processOrder(order: Order) {
  validateOrder(order);
  const totals = calculateTotals(order);
  const finalPrice = applyDiscounts(totals, order);
  sendConfirmation(order, finalPrice);
}

2. 重复代码

异味:相同代码出现在多个地方

重构:提取函数/类

// 之前
function formatUserName(user: User) {
  return `${user.firstName} ${user.lastName}`;
}

function formatAuthorName(author: Author) {
  return `${author.firstName} ${author.lastName}`;
}

// 之后
function formatFullName(person: { firstName: string; lastName: string }) {
  return `${person.firstName} ${person.lastName}`;
}

3. 长参数列表

异味:函数有4个以上参数

重构:参数对象

// 之前
function createUser(
  firstName: string,
  lastName: string,
  email: string,
  phone: string,
  address: string
) { }

// 之后
interface UserDetails {
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  address: string;
}

function createUser(details: UserDetails) { }

4. 大类

异味:类有许多责任

重构:提取类

// 之前
class UserManager {
  createUser() { }
  deleteUser() { }
  sendEmail() { }
  generateReport() { }
  logActivity() { }
}

// 之后
class UserService {
  createUser() { }
  deleteUser() { }
}

class EmailService {
  sendEmail() { }
}

class ReportService {
  generateReport() { }
}

5. 特征羡慕

异味:方法使用另一个类的数据多于自己类的数据

重构:移动方法

// 之前
class Order {
  calculate() {
    return this.customer.getDiscount() * this.amount;
  }
}

// 之后
class Customer {
  calculateOrderAmount(order: Order) {
    return this.getDiscount() * order.amount;
  }
}

重构技术

提取方法

将大函数分解为更小、有名称的部分:

// 之前
function renderUser(user: User) {
  console.log(`<div>`);
  console.log(`  <h1>${user.firstName} ${user.lastName}</h1>`);
  console.log(`  <p>${user.email}</p>`);
  console.log(`</div>`);
}

// 之后
function renderUser(user: User) {
  console.log(`<div>`);
  console.log(`  ${renderUserHeader(user)}`);
  console.log(`  ${renderUserEmail(user)}`);
  console.log(`</div>`);
}

function renderUserHeader(user: User) {
  return `<h1>${user.firstName} ${user.lastName}</h1>`;
}

function renderUserEmail(user: User) {
  return `<p>${user.email}</p>`;
}

重命名以清晰化

使用描述性名称:

// 之前
function calc(a: number, b: number) {
  return a * b * 0.08;
}

// 之后
function calculateSalesTax(amount: number, quantity: number) {
  const TAX_RATE = 0.08;
  return amount * quantity * TAX_RATE;
}

引入解释性变量

使复杂表达式清晰:

// 之前
if (platform.toUpperCase().includes('MAC') && 
    browser.toUpperCase().includes('IE') &&
    wasInitialized() && resized) {
  // 做某事
}

// 之后
const isMacOS = platform.toUpperCase().includes('MAC');
const isIE = browser.toUpperCase().includes('IE');
const wasResized = wasInitialized() && resized;

if (isMacOS && isIE && wasResized) {
  // 做某事
}

用多态替换条件

使用继承/接口代替switch/if-else链:

// 之前
function getSpeed(vehicle: Vehicle) {
  switch (vehicle.type) {
    case 'car': return vehicle.speed * 1.0;
    case 'bike': return vehicle.speed * 0.8;
    case 'truck': return vehicle.speed * 0.6;
  }
}

// 之后
interface Vehicle {
  getSpeed(): number;
}

class Car implements Vehicle {
  getSpeed() { return this.speed * 1.0; }
}

class Bike implements Vehicle {
  getSpeed() { return this.speed * 0.8; }
}

简化条件逻辑

使用早期返回和守卫子句:

// 之前
function processPayment(payment: Payment) {
  if (payment.isValid()) {
    if (payment.amount > 0) {
      if (payment.method === 'card') {
        // 处理卡片支付
      } else {
        // 无效方法
      }
    } else {
      // 无效金额
    }
  } else {
    // 无效支付
  }
}

// 之后
function processPayment(payment: Payment) {
  if (!payment.isValid()) {
    throw new Error('无效支付');
  }
  
  if (payment.amount <= 0) {
    throw new Error('无效金额');
  }
  
  if (payment.method !== 'card') {
    throw new Error('无效方法');
  }
  
  // 处理卡片支付
}

重构工作流

步骤1:理解当前代码

# 彻底阅读代码
cat src/feature.ts

# 检查测试
cat src/feature.test.ts

# 查找所有使用情况
grep -r "functionName" src/

步骤2:确保测试存在

# 运行现有测试
npm test src/feature.test.ts

# 如果需要,添加缺失测试

步骤3:小步重构

# 做一个重构更改
# 运行测试
npm test

# 如果测试通过,提交
git add . && git commit -m "重构:提取方法 calculateTotal"

# 重复下一个重构

步骤4:验证无回归

# 运行完整测试套件
npm test

# 检查类型错误
npx tsc --noEmit

# 验证代码检查
npm run lint

步骤5:性能检查

# 如果性能关键,比较前后性能
npm run benchmark

重构检查清单

重构前:

  • [ ] 测试存在并通过
  • [ ] 理解当前行为
  • [ ] 知道为什么需要重构
  • [ ] 有时间完成重构

重构中:

  • [ ] 一次只做一个更改
  • [ ] 每次更改后运行测试
  • [ ] 保持提交小而专注
  • [ ] 重构期间不要添加功能

重构后:

  • [ ] 所有测试通过
  • [ ] 无类型错误
  • [ ] 代码检查通过
  • [ ] 完成代码审查
  • [ ] 如果需要,更新文档

集成点

补充:

  • 验证循环:用于重构后的验证
  • TDD工作流:用于测试优先方法
  • 编码标准强制执行器:用于样式一致性
  • 测试模式:用于测试设计

重构反模式

不要

  • 没有测试的情况下重构
  • 将重构与功能工作混在一起
  • 一次做大的更改
  • 重构你不理解的代码
  • 跳过验证步骤

  • 先写测试
  • 分开重构提交
  • 做增量更改
  • 重构前理解代码
  • 频繁运行测试