Skip to content

代码重构

MyDeskBot 的智能代码重构功能帮助您改进代码结构、提高可维护性,同时保持功能不变。

目录

重构类型

1. 提取方法

将重复或复杂的代码块提取为独立方法:

重构前:

python
def process_users(users):
    for user in users:
        # 重复的验证逻辑
        if not user.email or '@' not in user.email:
            continue
        if not user.name:
            continue

        # 处理用户
        user.email = user.email.lower().strip()
        user.name = user.name.title()

重构后:

python
def is_valid_user(user):
    return user.email and '@' in user.email and user.name

def process_users(users):
    for user in users:
        if not is_valid_user(user):
            continue

        user.email = user.email.lower().strip()
        user.name = user.name.title()

2. 内联方法

将简单的方法调用内联:

重构前:

javascript
function getDiscountedPrice(price, discount) {
  return price * (1 - discount);
}

function calculateTotal(price, quantity, discount) {
  return getDiscountedPrice(price, discount) * quantity;
}

重构后:

javascript
function calculateTotal(price, quantity, discount) {
  return price * (1 - discount) * quantity;
}

3. 重命名变量/方法

使用更有意义的名称:

重构前:

java
public List<?> d(List<?> d, int c) {
    if (d == null) return Collections.emptyList();
    return d.stream().limit(c).collect(Collectors.toList());
}

重构后:

java
public List<?> takeFirstNElements(List<?> data, int count) {
    if (data == null) return Collections.emptyList();
    return data.stream().limit(count).collect(Collectors.toList());
}

4. 提取接口

从具体类中提取接口:

重构前:

typescript
class PostgreSQLDatabase {
  connect(): void {}
  query(sql: string): Promise<any> {}
  close(): void {}
}

class MySQLDatabase {
  connect(): void {}
  query(sql: string): Promise<any> {}
  close(): void {}
}

重构后:

typescript
interface Database {
  connect(): void;
  query(sql: string): Promise<any>;
  close(): void;
}

class PostgreSQLDatabase implements Database {}
class MySQLDatabase implements Database {}

5. 移除重复代码

消除重复逻辑:

重构前:

javascript
function createUser(name, email) {
  if (!name || name.trim() === "") {
    throw new Error("Name is required");
  }
  if (!email || email.trim() === "") {
    throw new Error("Email is required");
  }
  // ...
}

function updateUser(id, name, email) {
  if (!name || name.trim() === "") {
    throw new Error("Name is required");
  }
  if (!email || email.trim() === "") {
    throw new Error("Email is required");
  }
  // ...
}

重构后:

javascript
function validateName(name) {
  if (!name || name.trim() === "") {
    throw new Error("Name is required");
  }
}

function validateEmail(email) {
  if (!email || email.trim() === "") {
    throw new Error("Email is required");
  }
}

function createUser(name, email) {
  validateName(name);
  validateEmail(email);
  // ...
}

function updateUser(id, name, email) {
  validateName(name);
  validateEmail(email);
  // ...
}

6. 简化条件表达式

简化复杂的条件:

重构前:

python
if status == 'active' and user.role == 'admin' and not user.deleted:
    return True
else:
    return False

重构后:

python
def is_authorized(user):
    return (
        user.status == 'active'
        and user.role == 'admin'
        and not user.deleted
    )

7. 应用设计模式

MyDeskBot 可以识别机会并应用设计模式:

重构前:

java
public class ReportGenerator {
    public String generatePDFReport() { }
    public String generateHTMLReport() { }
    public String generateExcelReport() { }
}

重构后:

java
public interface ReportFormatter {
    String format(ReportData data);
}

public class PDFFormatter implements ReportFormatter { }
public class HTMLFormatter implements ReportFormatter { }
public class ExcelFormatter implements ReportFormatter { }

public class ReportGenerator {
    private final ReportFormatter formatter;

    public ReportGenerator(ReportFormatter formatter) {
        this.formatter = formatter;
    }

    public String generate(ReportData data) {
        return formatter.format(data);
    }
}

使用方式

IntelliJ IDEA

  1. 选中要重构的代码
  2. 右键 → RefactorRefactor with AI
  3. 描述重构目标或选择重构类型
  4. 预览变更
  5. 应用重构

VS Code

  1. 选中代码
  2. Ctrl+Shift+R (Windows/Linux) / Cmd+Shift+R (macOS)
  3. 或右键 → "Refactor with MyDeskBot"
  4. 查看建议的重构方案
  5. 接受或修改建议

Neovim

vim
" Visual 模式选中代码
:MyDeskBotRefactor

" 输入重构目标
" 提取这个函数

重构准则

1. 保持功能不变

重构必须不改变代码的外部行为:

python
# 重构前
def calculate_total(price, quantity, discount=0):
    return price * quantity * (1 - discount)

# 重构后 - 功能完全相同
def calculate_total(price, quantity, discount=0):
    subtotal = price * quantity
    discount_amount = subtotal * discount
    return subtotal - discount_amount

2. 小步重构

每次只做一个小改动,频繁测试:

javascript
// 第一步:提取常量
const TAX_RATE = 0.1;

// 第二步:提取方法
function calculateTax(amount) {
  return amount * TAX_RATE;
}

// 第三步:使用新方法
function withTax(price) {
  return price + calculateTax(price);
}

3. 运行测试

每次重构后运行测试确保没有破坏任何功能。

4. 提交代码

小步重构后提交代码,便于回滚。

示例场景

场景 1: 长方法重构

原始代码:

python
def process_order(order):
    # 验证订单
    if not order.customer_id:
        raise ValueError("Customer ID required")
    if not order.items:
        raise ValueError("Order must have items")

    # 计算总价
    total = 0
    for item in order.items:
        if item.price <= 0:
            raise ValueError("Invalid item price")
        if item.quantity <= 0:
            raise ValueError("Invalid item quantity")
        total += item.price * item.quantity

    # 应用折扣
    if order.customer_tier == 'premium':
        total *= 0.9
    elif order.customer_tier == 'gold':
        total *= 0.85

    # 检查库存
    for item in order.items:
        product = get_product(item.product_id)
        if product.stock < item.quantity:
            raise ValueError(f"Insufficient stock for {product.name}")

    # 创建订单记录
    db_order = OrderRecord(
        customer_id=order.customer_id,
        total=total,
        status='pending'
    )
    save_order(db_order)

    # 更新库存
    for item in order.items:
        update_stock(item.product_id, -item.quantity)

    # 发送通知
    send_email(order.customer_id, "Order confirmed", db_order.id)

    return db_order.id

重构后:

python
def process_order(order):
    validate_order(order)
    total = calculate_order_total(order)
    check_stock_availability(order)
    db_order = create_order_record(order, total)
    update_product_stock(order)
    send_confirmation(order, db_order.id)
    return db_order.id

def validate_order(order):
    if not order.customer_id:
        raise ValueError("Customer ID required")
    if not order.items:
        raise ValueError("Order must have items")

def calculate_order_total(order):
    total = 0
    for item in order.items:
        if item.price <= 0:
            raise ValueError("Invalid item price")
        if item.quantity <= 0:
            raise ValueError("Invalid item quantity")
        total += item.price * item.quantity

    discount = get_customer_discount(order.customer_tier)
    return total * (1 - discount)

def get_customer_discount(tier):
    discounts = {'premium': 0.1, 'gold': 0.15}
    return discounts.get(tier, 0)

def check_stock_availability(order):
    for item in order.items:
        product = get_product(item.product_id)
        if product.stock < item.quantity:
            raise ValueError(f"Insufficient stock for {product.name}")

def create_order_record(order, total):
    db_order = OrderRecord(
        customer_id=order.customer_id,
        total=total,
        status='pending'
    )
    save_order(db_order)
    return db_order

def update_product_stock(order):
    for item in order.items:
        update_stock(item.product_id, -item.quantity)

def send_confirmation(order, order_id):
    send_email(order.customer_id, "Order confirmed", order_id)

场景 2: 复杂条件简化

原始代码:

java
public boolean canAccess(User user, Resource resource) {
    if (user.isAdmin()) {
        if (resource.isPublic() || resource.isSharedWith(user)) {
            return true;
        } else {
            return false;
        }
    } else if (user.isPremium() && resource.isPremium()) {
        if (user.hasSubscription() && !user.isExpired()) {
            return true;
        } else {
            return false;
        }
    } else if (resource.isPublic()) {
        return true;
    } else if (resource.isSharedWith(user)) {
        return true;
    } else {
        return false;
    }
}

重构后:

java
public boolean canAccess(User user, Resource resource) {
    return isAccessibleByAdmin(user, resource)
        || isAccessibleByPremiumUser(user, resource)
        || isPublicOrShared(resource, user);
}

private boolean isAccessibleByAdmin(User user, Resource resource) {
    return user.isAdmin() &&
        (resource.isPublic() || resource.isSharedWith(user));
}

private boolean isAccessibleByPremiumUser(User user, Resource resource) {
    return user.isPremium()
        && resource.isPremium()
        && user.hasActiveSubscription();
}

private boolean isPublicOrShared(Resource resource, User user) {
    return resource.isPublic() || resource.isSharedWith(user);
}

场景 3: 策略模式应用

原始代码:

typescript
function calculateShipping(type: string, weight: number, distance: number) {
  if (type === "standard") {
    return weight * 0.5 + distance * 0.1;
  } else if (type === "express") {
    return weight * 0.8 + distance * 0.2 + 10;
  } else if (type === "overnight") {
    return weight * 1.2 + distance * 0.3 + 20;
  }
  throw new Error("Invalid shipping type");
}

重构后:

typescript
interface ShippingStrategy {
  calculate(weight: number, distance: number): number;
}

class StandardShipping implements ShippingStrategy {
  calculate(weight: number, distance: number): number {
    return weight * 0.5 + distance * 0.1;
  }
}

class ExpressShipping implements ShippingStrategy {
  calculate(weight: number, distance: number): number {
    return weight * 0.8 + distance * 0.2 + 10;
  }
}

class OvernightShipping implements ShippingStrategy {
  calculate(weight: number, distance: number): number {
    return weight * 1.2 + distance * 0.3 + 20;
  }
}

class ShippingCalculator {
  private strategies: Map<string, ShippingStrategy> = new Map();

  constructor() {
    this.strategies.set("standard", new StandardShipping());
    this.strategies.set("express", new ExpressShipping());
    this.strategies.set("overnight", new OvernightShipping());
  }

  calculate(type: string, weight: number, distance: number): number {
    const strategy = this.strategies.get(type);
    if (!strategy) {
      throw new Error("Invalid shipping type");
    }
    return strategy.calculate(weight, distance);
  }
}

最佳实践

  1. 有测试覆盖: 确保有足够的测试后再重构
  2. 小步前进: 每次只做一个小改动
  3. 频繁测试: 每次改动后运行测试
  4. 版本控制: 重构前创建分支或提交
  5. 团队沟通: 重构前与团队沟通意图
  6. 文档更新: 重构后更新相关文档

下一步