code-refactoring
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCode Refactoring
代码重构
Refactoring Principles
重构原则
When to Refactor
何时进行重构
- Before adding new features (make change easy, then make easy change)
- After getting tests passing (red-green-refactor)
- When you see code smells
- During code review feedback
- 添加新功能之前(先让修改变简单,再做简单的修改)
- 测试通过之后(红-绿-重构流程)
- 发现代码坏味道时
- 根据代码评审反馈进行
When NOT to Refactor
何时不进行重构
- Without tests covering the code
- Under tight deadlines with no safety net
- Code that will be replaced soon
- When you don't understand what the code does
- 没有测试覆盖代码时
- 时间紧迫且无安全保障时
- 即将被替换的代码
- 你不理解代码功能时
Common Code Smells
常见代码坏味道
Long Methods
过长方法
typescript
// BEFORE: Method doing too much
function processOrder(order: Order) {
// 100 lines of validation, calculation, notification, logging...
}
// AFTER: Extract into focused methods
function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
saveOrder(order, total);
notifyCustomer(order);
}typescript
// 重构前:方法职责过多
function processOrder(order: Order) {
// 包含100行验证、计算、通知、日志等代码...
}
// 重构后:拆分为单一职责方法
function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
saveOrder(order, total);
notifyCustomer(order);
}Deeply Nested Conditionals
深层嵌套条件
typescript
// BEFORE: Arrow code
function getDiscount(user: User, order: Order) {
if (user) {
if (user.isPremium) {
if (order.total > 100) {
if (order.items.length > 5) {
return 0.2;
}
}
}
}
return 0;
}
// AFTER: Early returns (guard clauses)
function getDiscount(user: User, order: Order) {
if (!user) return 0;
if (!user.isPremium) return 0;
if (order.total <= 100) return 0;
if (order.items.length <= 5) return 0;
return 0.2;
}typescript
// 重构前:箭头代码
function getDiscount(user: User, order: Order) {
if (user) {
if (user.isPremium) {
if (order.total > 100) {
if (order.items.length > 5) {
return 0.2;
}
}
}
}
return 0;
}
// 重构后:提前返回(守卫子句)
function getDiscount(user: User, order: Order) {
if (!user) return 0;
if (!user.isPremium) return 0;
if (order.total <= 100) return 0;
if (order.items.length <= 5) return 0;
return 0.2;
}Primitive Obsession
基本类型偏执
typescript
// BEFORE: Primitives everywhere
function createUser(name: string, email: string, phone: string) {
if (!email.includes('@')) throw new Error('Invalid email');
// more validation...
}
// AFTER: Value objects
class Email {
constructor(private value: string) {
if (!value.includes('@')) throw new Error('Invalid email');
}
toString() { return this.value; }
}
function createUser(name: string, email: Email, phone: Phone) {
// Email is already validated
}typescript
// 重构前:到处使用基本类型
function createUser(name: string, email: string, phone: string) {
if (!email.includes('@')) throw new Error('Invalid email');
// 更多验证逻辑...
}
// 重构后:使用值对象
class Email {
constructor(private value: string) {
if (!value.includes('@')) throw new Error('Invalid email');
}
toString() { return this.value; }
}
function createUser(name: string, email: Email, phone: Phone) {
// Email已完成验证
}Feature Envy
特性依恋
typescript
// BEFORE: Method uses another object's data extensively
function calculateShipping(order: Order) {
const address = order.customer.address;
const weight = order.items.reduce((sum, i) => sum + i.weight, 0);
const distance = calculateDistance(address.zip);
return weight * distance * 0.01;
}
// AFTER: Move method to where the data is
class Order {
calculateShipping() {
return this.totalWeight * this.customer.shippingDistance * 0.01;
}
}typescript
// 重构前:方法过度依赖另一个对象的数据
function calculateShipping(order: Order) {
const address = order.customer.address;
const weight = order.items.reduce((sum, i) => sum + i.weight, 0);
const distance = calculateDistance(address.zip);
return weight * distance * 0.01;
}
// 重构后:将方法移至数据所属对象
class Order {
calculateShipping() {
return this.totalWeight * this.customer.shippingDistance * 0.01;
}
}Refactoring Techniques
重构技巧
Extract Method
提取方法
typescript
// Identify a code block that does one thing
// Move it to a new method with a descriptive name
// Replace original code with method call
function printReport(data: ReportData) {
// Extract this block...
const header = `Report: ${data.title}\nDate: ${data.date}\n${'='.repeat(40)}`;
console.log(header);
// ...into a method
printHeader(data);
}typescript
// 识别出单一职责的代码块
// 将其移至新方法并赋予描述性名称
// 用方法调用替换原代码
function printReport(data: ReportData) {
// 提取这段代码...
const header = `Report: ${data.title}\nDate: ${data.date}\n${'='.repeat(40)}`;
console.log(header);
// ...到新方法中
printHeader(data);
}Replace Conditional with Polymorphism
用多态替换条件语句
typescript
// BEFORE: Switch on type
function getArea(shape: Shape) {
switch (shape.type) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'rectangle': return shape.width * shape.height;
case 'triangle': return shape.base * shape.height / 2;
}
}
// AFTER: Polymorphic classes
interface Shape {
getArea(): number;
}
class Circle implements Shape {
constructor(private radius: number) {}
getArea() { return Math.PI * this.radius ** 2; }
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
getArea() { return this.width * this.height; }
}typescript
// 重构前:根据类型使用switch语句
function getArea(shape: Shape) {
switch (shape.type) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'rectangle': return shape.width * shape.height;
case 'triangle': return shape.base * shape.height / 2;
}
}
// 重构后:使用多态类
interface Shape {
getArea(): number;
}
class Circle implements Shape {
constructor(private radius: number) {}
getArea() { return Math.PI * this.radius ** 2; }
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
getArea() { return this.width * this.height; }
}Introduce Parameter Object
引入参数对象
typescript
// BEFORE: Too many parameters
function searchProducts(
query: string,
minPrice: number,
maxPrice: number,
category: string,
inStock: boolean,
sortBy: string,
sortOrder: string
) { ... }
// AFTER: Parameter object
interface SearchParams {
query: string;
priceRange: { min: number; max: number };
category?: string;
inStock?: boolean;
sort?: { by: string; order: 'asc' | 'desc' };
}
function searchProducts(params: SearchParams) { ... }typescript
// 重构前:参数过多
function searchProducts(
query: string,
minPrice: number,
maxPrice: number,
category: string,
inStock: boolean,
sortBy: string,
sortOrder: string
) { ... }
// 重构后:使用参数对象
interface SearchParams {
query: string;
priceRange: { min: number; max: number };
category?: string;
inStock?: boolean;
sort?: { by: string; order: 'asc' | 'desc' };
}
function searchProducts(params: SearchParams) { ... }Replace Magic Numbers with Constants
用常量替换魔法值
typescript
// BEFORE
if (user.age >= 18 && order.total >= 50) {
applyDiscount(order, 0.1);
}
// AFTER
const MINIMUM_AGE = 18;
const DISCOUNT_THRESHOLD = 50;
const STANDARD_DISCOUNT = 0.1;
if (user.age >= MINIMUM_AGE && order.total >= DISCOUNT_THRESHOLD) {
applyDiscount(order, STANDARD_DISCOUNT);
}typescript
// 重构前
if (user.age >= 18 && order.total >= 50) {
applyDiscount(order, 0.1);
}
// 重构后
const MINIMUM_AGE = 18;
const DISCOUNT_THRESHOLD = 50;
const STANDARD_DISCOUNT = 0.1;
if (user.age >= MINIMUM_AGE && order.total >= DISCOUNT_THRESHOLD) {
applyDiscount(order, STANDARD_DISCOUNT);
}Safe Refactoring Process
安全重构流程
- Ensure tests exist - Write tests if they don't
- Make small changes - One refactoring at a time
- Run tests after each change - Catch regressions immediately
- Commit frequently - Easy to revert if something breaks
- Review the diff - Make sure behavior hasn't changed
- 确保测试存在 - 若没有则编写测试
- 做出小修改 - 每次只进行一项重构
- 每次修改后运行测试 - 立即捕获回归问题
- 频繁提交 - 若出现问题可轻松回滚
- 检查差异 - 确保行为未发生改变
Refactoring Checklist
重构检查清单
- Tests pass before starting
- Each change is small and focused
- Tests pass after each change
- No behavior changes (only structure)
- Code is more readable than before
- Commit message explains the refactoring
- 开始前测试已通过
- 每项修改都小而聚焦
- 每次修改后测试都通过
- 未改变行为(仅调整结构)
- 代码比之前更易读
- 提交信息说明重构内容