name: code-refactoring-patterns description: 系统化重构代码的方法,用于提高可维护性、性能和清晰度,同时保持功能不变 license: MIT metadata: adapted-by: ai-skills category: code-quality
代码重构模式
一个全面指南,用于在保持功能的同时重构代码并提高质量。
何时重构
- 检测到代码异味(如重复代码、长函数等)
- 在向复杂区域添加新功能之前
- 理解改进后(“现在我看到了更好的方法”)
- 当有测试在用时
- 需要性能优化时
重构规则
- 永不重构而无测试:如果没有测试,先写测试
- 小步骤:一次只做一个更改
- 每次更改后运行测试:确保没有破坏任何东西
- 经常提交:每个工作的重构都是一个提交
- 不要将重构与功能工作混合:分离关注点
常见代码异味
1. 长方法/函数
异味:函数超过20-30行
重构:提取方法
// 之前
function processOrder(order: Order) {
// 验证订单(10行)
// 计算总计(15行)
// 应用折扣(12行)
// 发送确认(8行)
}
// 之后
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 "refactor: extract method calculateTotal"
# 重复下一个重构
步骤4:验证无回归
# 运行完整测试套件
npm test
# 检查类型错误
npx tsc --noEmit
# 验证lint
npm run lint
步骤5:性能检查
# 如果性能关键,比较前后
npm run benchmark
重构检查清单
重构前:
- [ ] 测试存在且通过
- [ ] 理解当前行为
- [ ] 知道为什么需要重构
- [ ] 有时间完成重构
重构期间:
- [ ] 一次只做一个更改
- [ ] 每次更改后运行测试
- [ ] 保持提交小而专注
- [ ] 重构期间不添加功能
重构后:
- [ ] 所有测试通过
- [ ] 无类型错误
- [ ] Lint通过
- [ ] 代码审查完成
- [ ] 如果需要,更新文档
集成点
补充:
- verification-loop:用于重构后的验证
- tdd-workflow:用于测试优先方法
- coding-standards-enforcer:用于样式一致性
- testing-patterns:用于测试设计
重构反模式
❌ 不要:
- 无测试重构
- 将重构与功能工作混合
- 一次性做大型更改
- 重构你不理解的代码
- 跳过验证步骤
✅ 要做:
- 先写测试
- 分离重构提交
- 做增量更改
- 重构前理解代码
- 频繁运行测试