代码重构Skill refactor

代码重构技能用于通过手术式代码优化来提高软件的可维护性和可读性,而不改变外部行为。它包括提取函数、重命名变量、分解庞大函数、改进类型安全、消除代码异味和应用设计模式等操作。适用于软件开发中的代码优化和维护,关键词:代码重构、软件维护、代码优化、设计模式、可读性、渐进改进。

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

name: 代码重构 description: ‘通过手术式代码重构提高可维护性而不改变行为。涵盖提取函数、重命名变量、分解庞大函数、改进类型安全、消除代码异味和应用设计模式。不像仓库重建那样剧烈;用于渐进改进。’ license: MIT

代码重构

概述

改进代码结构和可读性而不改变外部行为。重构是渐进演变,不是革命。用于改进现有代码,而不是从头重写。

何时使用

使用此技能当:

  • 代码难以理解或维护
  • 函数/类太大
  • 需要处理代码异味
  • 由于代码结构导致添加功能困难
  • 用户要求“清理此代码”、“重构此代码”、“改进此代码”

重构原则

黄金法则

  1. 行为保持不变 - 重构不改变代码的功能,只改变其方式
  2. 小步骤 - 进行微小更改,每次测试
  3. 版本控制是你的朋友 - 在每个安全状态前和后提交
  4. 测试是必不可少的 - 没有测试,你不是重构,而是在编辑
  5. 一次只做一件事 - 不要将重构与功能更改混合

何时不应重构

- 代码工作且不再更改(如果没坏...)
- 没有测试的关键生产代码(先添加测试)
- 当你处于紧张期限下时
- “仅仅因为” - 需要明确目的

常见代码异味与修复

1. 长方法/函数

# 错误:200行函数做所有事情
- async function processOrder(orderId) {
-   // 50行:获取订单
-   // 30行:验证订单
-   // 40行:计算价格
-   // 30行:更新库存
-   // 20行:创建运输
-   // 30行:发送通知
- }

# 正确:分解为专注函数
+ async function processOrder(orderId) {
+   const order = await fetchOrder(orderId);
+   validateOrder(order);
+   const pricing = calculatePricing(order);
+   await updateInventory(order);
+   const shipment = await createShipment(order);
+   await sendNotifications(order, pricing, shipment);
+   return { order, pricing, shipment };
+ }

2. 重复代码

# 错误:相同逻辑在多处
- function calculateUserDiscount(user) {
-   if (user.membership === 'gold') return user.total * 0.2;
-   if (user.membership === 'silver') return user.total * 0.1;
-   return 0;
- }
-
- function calculateOrderDiscount(order) {
-   if (order.user.membership === 'gold') return order.total * 0.2;
-   if (order.user.membership === 'silver') return order.total * 0.1;
-   return 0;
- }

# 正确:提取共同逻辑
+ function getMembershipDiscountRate(membership) {
+   const rates = { gold: 0.2, silver: 0.1 };
+   return rates[membership] || 0;
+ }
+
+ function calculateUserDiscount(user) {
+   return user.total * getMembershipDiscountRate(user.membership);
+ }
+
+ function calculateOrderDiscount(order) {
+   return order.total * getMembershipDiscountRate(order.user.membership);
+ }

3. 大类/模块

# 错误:上帝对象知道太多
- class UserManager {
-   createUser() { /* ... */ }
-   updateUser() { /* ... */ }
-   deleteUser() { /* ... */ }
-   sendEmail() { /* ... */ }
-   generateReport() { /* ... */ }
-   handlePayment() { /* ... */ }
-   validateAddress() { /* ... */ }
-   // 50更多方法...
- }

# 正确:每个类单一职责
+ class UserService {
+   create(data) { /* ... */ }
+   update(id, data) { /* ... */ }
+   delete(id) { /* ... */ }
+ }
+
+ class EmailService {
+   send(to, subject, body) { /* ... */ }
+ }
+
+ class ReportService {
+   generate(type, params) { /* ... */ }
+ }
+
+ class PaymentService {
+   process(amount, method) { /* ... */ }
+ }

4. 长参数列表

# 错误:参数太多
- function createUser(email, password, name, age, address, city, country, phone) {
-   /* ... */
- }

# 正确:分组相关参数
+ interface UserData {
+   email: string;
+   password: string;
+   name: string;
+   age?: number;
+   address?: Address;
+   phone?: string;
+ }
+
+ function createUser(data: UserData) {
+   /* ... */
+ }

# 更好:对复杂构造使用建造者模式
+ const user = UserBuilder
+   .email('test@example.com')
+   .password('secure123')
+   .name('Test User')
+   .address(address)
+   .build();

5. 特性嫉妒

# 错误:方法使用另一个对象的数据多于自己的
- class Order {
-   calculateDiscount(user) {
-     if (user.membershipLevel === 'gold') {
+       return this.total * 0.2;
+     }
+     if (user.accountAge > 365) {
+       return this.total * 0.1;
+     }
+     return 0;
+   }
+ }

# 正确:将逻辑移到拥有数据的对象
+ class User {
+   getDiscountRate(orderTotal) {
+     if (this.membershipLevel === 'gold') return 0.2;
+     if (this.accountAge > 365) return 0.1;
+     return 0;
+   }
+ }
+
+ class Order {
+   calculateDiscount(user) {
+     return this.total * user.getDiscountRate(this.total);
+   }
+ }

6. 基本类型迷恋

# 错误:对域概念使用基本类型
- function sendEmail(to, subject, body) { /* ... */ }
- sendEmail('user@example.com', 'Hello', '...');
-
- function createPhone(country, number) {
-   return `${country}-${number}`;
- }

# 正确:使用域类型
+ class Email {
+   private constructor(public readonly value: string) {
+     if (!Email.isValid(value)) throw new Error('无效邮箱');
+   }
+   static create(value: string) { return new Email(value); }
+   static isValid(email: string) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); }
+ }
+
+ class PhoneNumber {
+   constructor(
+     public readonly country: string,
+     public readonly number: string
+   ) {
+     if (!PhoneNumber.isValid(country, number)) throw new Error('无效电话');
+   }
+   toString() { return `${this.country}-${this.number}`; }
+   static isValid(country: string, number: string) { /* ... */ }
+ }
+
+ // 用法
+ const email = Email.create('user@example.com');
+ const phone = new PhoneNumber('1', '555-1234');

7. 魔法数字/字符串

# 错误:未解释的值
- if (user.status === 2) { /* ... */ }
- const discount = total * 0.15;
- setTimeout(callback, 86400000);

# 正确:命名常量
+ const UserStatus = {
+   ACTIVE: 1,
+   INACTIVE: 2,
+   SUSPENDED: 3
+ } as const;
+
+ const DISCOUNT_RATES = {
+   STANDARD: 0.1,
+   PREMIUM: 0.15,
+   VIP: 0.2
+ } as const;
+
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
+
+ if (user.status === UserStatus.INACTIVE) { /* ... */ }
+ const discount = total * DISCOUNT_RATES.PREMIUM;
+ setTimeout(callback, ONE_DAY_MS);

8. 嵌套条件

# 错误:箭头代码
- function process(order) {
-   if (order) {
-     if (order.user) {
-       if (order.user.isActive) {
-         if (order.total > 0) {
-           return processOrder(order);
+         } else {
+           return { error: '无效总计' };
+         }
+       } else {
+         return { error: '用户不活跃' };
+       }
+     } else {
+       return { error: '无用户' };
+     }
+   } else {
+     return { error: '无订单' };
+   }
+ }

# 正确:守卫子句 / 早期返回
+ function process(order) {
+   if (!order) return { error: '无订单' };
+   if (!order.user) return { error: '无用户' };
+   if (!order.user.isActive) return { error: '用户不活跃' };
+   if (order.total <= 0) return { error: '无效总计' };
+   return processOrder(order);
+ }

# 更好:使用结果类型
+ function process(order): Result<ProcessedOrder, Error> {
+   return Result.combine([
+     validateOrderExists(order),
+     validateUserExists(order),
+     validateUserActive(order.user),
+     validateOrderTotal(order)
+   ]).flatMap(() => processOrder(order));
+ }

9. 死代码

# 错误:未使用代码残留
- function oldImplementation() { /* ... */ }
- const DEPRECATED_VALUE = 5;
- import { unusedThing } from './somewhere';
- // 注释掉代码
- // function oldCode() { /* ... */ }

# 正确:删除它
+ // 删除未使用的函数、导入和注释代码
+ // 如果需要,Git历史中有它

10. 不适当亲密

# 错误:一个类深入访问另一个
- class OrderProcessor {
-   process(order) {
-     order.user.profile.address.street;  // 太亲密
-     order.repository.connection.config;  // 破坏封装
+   }
+ }

# 正确:询问,不要告诉
+ class OrderProcessor {
+   process(order) {
+     order.getShippingAddress();  // 订单知道如何获取
+     order.save();  // 订单知道如何保存自己
+   }
+ }

提取方法重构

前后对比

# 之前:一个长函数
- function printReport(users) {
-   console.log('USER REPORT');
-   console.log('============');
-   console.log('');
-   console.log(`Total users: ${users.length}`);
-   console.log('');
-   console.log('ACTIVE USERS');
-   console.log('------------');
-   const active = users.filter(u => u.isActive);
-   active.forEach(u => {
-     console.log(`- ${u.name} (${u.email})`);
-   });
-   console.log('');
-   console.log(`Active: ${active.length}`);
-   console.log('');
-   console.log('INACTIVE USERS');
-   console.log('--------------');
-   const inactive = users.filter(u => !u.isActive);
-   inactive.forEach(u => {
-     console.log(`- ${u.name} (${u.email})`);
-   });
-   console.log('');
-   console.log(`Inactive: ${inactive.length}`);
- }

# 之后:提取的方法
+ function printReport(users) {
+   printHeader('USER REPORT');
+   console.log(`Total users: ${users.length}
`);
+   printUserSection('ACTIVE USERS', users.filter(u => u.isActive));
+   printUserSection('INACTIVE USERS', users.filter(u => !u.isActive));
+ }
+
+ function printHeader(title) {
+   const line = '='.repeat(title.length);
+   console.log(title);
+   console.log(line);
+   console.log('');
+ }
+
+ function printUserSection(title, users) {
+   console.log(title);
+   console.log('-'.repeat(title.length));
+   users.forEach(u => console.log(`- ${u.name} (${u.email})`));
+   console.log('');
+   console.log(`${title.split(' ')[0]}: ${users.length}`);
+   console.log('');
+ }

引入类型安全

从无类型到有类型

# 之前:无类型
- function calculateDiscount(user, total, membership, date) {
-   if (membership === 'gold' && date.getDay() === 5) {
-     return total * 0.25;
-   }
-   if (membership === 'gold') return total * 0.2;
-   return total * 0.1;
- }

# 之后:完全类型安全
+ type Membership = 'bronze' | 'silver' | 'gold';
+
+ interface User {
+   id: string;
+   name: string;
+   membership: Membership;
+ }
+
+ interface DiscountResult {
+   original: number;
+   discount: number;
+   final: number;
+   rate: number;
+ }
+
+ function calculateDiscount(
+   user: User,
+   total: number,
+   date: Date = new Date()
+ ): DiscountResult {
+   if (total < 0) throw new Error('总计不能为负');
+
+   let rate = 0.1; // 默认青铜
+
+   if (user.membership === 'gold' && date.getDay() === 5) {
+     rate = 0.25; // 金会员周五奖金
+   } else if (user.membership === 'gold') {
+     rate = 0.2;
+   } else if (user.membership === 'silver') {
+     rate = 0.15;
+   }
+
+   const discount = total * rate;
+
+   return {
+     original: total,
+     discount,
+     final: total - discount,
+     rate
+   };
+ }

重构的设计模式

策略模式

# 之前:条件逻辑
- function calculateShipping(order, method) {
-   if (method === 'standard') {
-     return order.total > 50 ? 0 : 5.99;
-   } else if (method === 'express') {
-     return order.total > 100 ? 9.99 : 14.99;
+   } else if (method === 'overnight') {
+     return 29.99;
+   }
+ }

# 之后:策略模式
+ interface ShippingStrategy {
+   calculate(order: Order): number;
+ }
+
+ class StandardShipping implements ShippingStrategy {
+   calculate(order: Order) {
+     return order.total > 50 ? 0 : 5.99;
+   }
+ }
+
+ class ExpressShipping implements ShippingStrategy {
+   calculate(order: Order) {
+     return order.total > 100 ? 9.99 : 14.99;
+   }
+ }
+
+ class OvernightShipping implements ShippingStrategy {
+   calculate(order: Order) {
+     return 29.99;
+   }
+ }
+
+ function calculateShipping(order: Order, strategy: ShippingStrategy) {
+   return strategy.calculate(order);
+ }

责任链模式

# 之前:嵌套验证
- function validate(user) {
-   const errors = [];
-   if (!user.email) errors.push('需要邮箱');
+   else if (!isValidEmail(user.email)) errors.push('无效邮箱');
+   if (!user.name) errors.push('需要名称');
+   if (user.age < 18) errors.push('必须18岁以上');
+   if (user.country === 'blocked') errors.push('国家不支持');
+   return errors;
+ }

# 之后:责任链模式
+ abstract class Validator {
+   abstract validate(user: User): string | null;
+   setNext(validator: Validator): Validator {
+     this.next = validator;
+     return validator;
+   }
+   validate(user: User): string | null {
+     const error = this.doValidate(user);
+     if (error) return error;
+     return this.next?.validate(user) ?? null;
+   }
+ }
+
+ class EmailRequiredValidator extends Validator {
+   doValidate(user: User) {
+     return !user.email ? '需要邮箱' : null;
+   }
+ }
+
+ class EmailFormatValidator extends Validator {
+   doValidate(user: User) {
+     return user.email && !isValidEmail(user.email) ? '无效邮箱' : null;
+   }
+ }
+
+ // 构建链
+ const validator = new EmailRequiredValidator()
+   .setNext(new EmailFormatValidator())
+   .setNext(new NameRequiredValidator())
+   .setNext(new AgeValidator())
+   .setNext(new CountryValidator());

重构步骤

安全重构过程

1. 准备
   - 确保测试存在(如果缺失则编写)
   - 提交当前状态
   - 创建功能分支

2. 识别
   - 找到要处理的代码异味
   - 理解代码功能
   - 计划重构

3. 重构(小步骤)
   - 做一个小更改
   - 运行测试
   - 如果测试通过则提交
   - 重复

4. 验证
   - 所有测试通过
   - 如果需要,手动测试
   - 性能不变或改进

5. 清理
   - 更新注释
   - 更新文档
   - 最终提交

重构清单

代码质量

  • [ ] 函数小(< 50行)
  • [ ] 函数做一件事
  • [ ] 无重复代码
  • [ ] 描述性名称(变量、函数、类)
  • [ ] 无魔法数字/字符串
  • [ ] 删除死代码

结构

  • [ ] 相关代码在一起
  • [ ] 清晰的模块边界
  • [ ] 依赖单向流动
  • [ ] 无循环依赖

类型安全

  • [ ] 为所有公共API定义类型
  • [ ] 无any类型,除非有正当理由
  • [ ] 可空类型明确标记

测试

  • [ ] 重构代码经过测试
  • [ ] 测试覆盖边缘情况
  • [ ] 所有测试通过

常见重构操作

操作 描述
提取方法 将代码片段转为方法
提取类 将行为移到新类
提取接口 从实现创建接口
内联方法 将方法体移回调用者
内联类 将类行为移到调用者
上拉方法 将方法移到超类
下推方法 将方法移到子类
重命名方法/变量 提高清晰度
引入参数对象 分组相关参数
用多态替换条件 使用多态代替switch/if
用常量替换魔法数字 命名常量
分解条件 分解复杂条件
合并条件 合并重复条件
用守卫子句替换嵌套条件 早期返回
引入空对象 消除空检查
用类/枚举替换类型代码 强类型
用委托替换继承 组合优于继承