目录

  • 每日一句正能量
  • 摘要
  • 一、引言:为什么代码重构如此重要?
  • 二、代码坏味道识别
  • 2.1 常见代码坏味道
  • 2.2 坏味道识别实现
  • 三、重构手法
  • 3.1 常用重构手法
  • 3.2 重构手法实现
  • 四、设计模式应用
  • 4.1 常用设计模式
  • 4.2 设计模式实现
  • 五、自动化重构工具
  • 5.1 DevEco Studio重构工具
  • 5.2 自动化重构实现
  • 六、重构实践
  • 6.1 重构流程
  • 6.2 重构实践示例
  • 七、常见问题与解决
  • 八、结语:代码重构是持续改进的"阶梯"


在这里插入图片描述

每日一句正能量

主动选择,接纳周期
有些路你必须一个人走,这不是孤独,而是选择。

相信"代码重构是持续改进的阶梯"。

摘要

摘要:代码重构是提升代码质量的重要手段。本文深入探讨DevEco Studio中的代码重构技巧,从代码坏味道识别、重构手法到设计模式应用,提供HarmonyOS代码重构的完整实践方案,帮助开发者打造高质量的代码。


一、引言:为什么代码重构如此重要?

"代码越写越乱,维护成本越来越高。"

"新功能开发越来越慢,因为代码耦合太严重。"

"Bug越来越多,修改一处影响多处。"

代码重构是提升代码质量的重要手段:

  • 提高可维护性:清晰的代码结构降低维护成本
  • 增强可扩展性:松耦合的代码更容易扩展
  • 减少Bug:消除代码坏味道,减少潜在问题
  • 提升开发效率:高质量的代码让开发更顺畅

二、代码坏味道识别

2.1 常见代码坏味道

在这里插入图片描述

图1:代码坏味道——重复代码、过长函数、过大类、过长参数列表、发散式变化、霰弹式修改

坏味道描述危害重构手法
重复代码相同或相似代码多处出现维护困难提取函数
过长函数函数行数过多难以理解提取函数
过大类类职责过多耦合严重提取类
过长参数列表参数过多难以使用引入参数对象
发散式变化一个类受多种变化影响修改困难拆分类
霰弹式修改修改一处需要修改多处遗漏风险移动函数
依恋情节函数过多使用其他类数据耦合严重移动函数
数据泥团相同数据多处出现重复代码提取类

2.2 坏味道识别实现

// 代码坏味道检测器
class CodeSmellDetector {
  private code: string
  private smells: CodeSmell[] = []

  constructor(code: string) {
    this.code = code
  }

  // 检测代码坏味道
  detectSmells(): CodeSmell[] {
    this.smells = []
    
    // 检测重复代码
    this.detectDuplicateCode()
    
    // 检测过长函数
    this.detectLongFunctions()
    
    // 检测过大类
    this.detectLargeClasses()
    
    // 检测过长参数列表
    this.detectLongParameterLists()
    
    return this.smells
  }

  // 检测重复代码
  private detectDuplicateCode(): void {
    const lines = this.code.split('\n')
    const codeBlocks: Map<string, number[]> = new Map()
    
    // 收集代码块
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i].trim()
      
      if (line.length > 10) { // 忽略短行
        const existingLines = codeBlocks.get(line) || []
        existingLines.push(i)
        codeBlocks.set(line, existingLines)
      }
    }
    
    // 检测重复
    for (const [line, lineNumbers] of codeBlocks) {
      if (lineNumbers.length > 1) {
        this.smells.push({
          type: 'duplicate_code',
          description: `重复代码: "${line.substring(0, 50)}..."`,
          locations: lineNumbers,
          severity: 'medium'
        })
      }
    }
  }

  // 检测过长函数
  private detectLongFunctions(): void {
    const functionRegex = /(?:function|async\s+function)\s+(\w+)\s*\([^)]*\)\s*\{([^}]*)\}/g
    let match
    
    while ((match = functionRegex.exec(this.code)) !== null) {
      const functionName = match[1]
      const functionBody = match[2]
      const lines = functionBody.split('\n').length
      
      if (lines > 50) {
        this.smells.push({
          type: 'long_function',
          description: `函数 "${functionName}" 过长 (${lines} 行)`,
          locations: [this.code.substring(0, match.index).split('\n').length],
          severity: lines > 100 ? 'high' : 'medium'
        })
      }
    }
  }

  // 检测过大类
  private detectLargeClasses(): void {
    const classRegex = /class\s+(\w+)\s*\{([^}]*)\}/g
    let match
    
    while ((match = classRegex.exec(this.code)) !== null) {
      const className = match[1]
      const classBody = match[2]
      const lines = classBody.split('\n').length
      
      if (lines > 200) {
        this.smells.push({
          type: 'large_class',
          description: `类 "${className}" 过大 (${lines} 行)`,
          locations: [this.code.substring(0, match.index).split('\n').length],
          severity: lines > 500 ? 'high' : 'medium'
        })
      }
    }
  }

  // 检测过长参数列表
  private detectLongParameterLists(): void {
    const functionRegex = /(?:function|async\s+function)\s+(\w+)\s*\(([^)]*)\)/g
    let match
    
    while ((match = functionRegex.exec(this.code)) !== null) {
      const functionName = match[1]
      const params = match[2].split(',').filter(p => p.trim().length > 0)
      
      if (params.length > 5) {
        this.smells.push({
          type: 'long_parameter_list',
          description: `函数 "${functionName}" 参数过多 (${params.length} 个)`,
          locations: [this.code.substring(0, match.index).split('\n').length],
          severity: params.length > 8 ? 'high' : 'medium'
        })
      }
    }
  }
}

// 代码坏味道
interface CodeSmell {
  type: string
  description: string
  locations: number[]
  severity: 'low' | 'medium' | 'high'
}

三、重构手法

3.1 常用重构手法

在这里插入图片描述

图2:重构手法——提取函数、内联函数、移动函数、提取类、内联类、替换算法

重构手法描述适用场景注意事项
提取函数将代码块提取为函数过长函数命名要清晰
内联函数将函数内联到调用处函数过于简单不要过度内联
移动函数将函数移到合适的类依恋情节保持职责单一
提取类将相关数据提取为新类数据泥团保持内聚性
内联类将类内联到使用处类过于简单考虑是否真的需要
替换算法用更清晰的算法替换算法复杂确保正确性
引入参数对象将参数封装为对象参数过多保持对象简单
以查询取代临时变量用函数替代临时变量临时变量过多避免重复计算

3.2 重构手法实现

// 重构工具
class RefactoringTool {
  private code: string

  constructor(code: string) {
    this.code = code
  }

  // 提取函数
  extractFunction(startLine: number, endLine: number, functionName: string): string {
    const lines = this.code.split('\n')
    const extractedLines = lines.slice(startLine, endLine + 1)
    const extractedCode = extractedLines.join('\n')
    
    // 分析参数
    const params = this.analyzeParameters(extractedCode)
    
    // 生成新函数
    const newFunction = `function ${functionName}(${params.join(', ')}) {\n${extractedCode}\n}`
    
    // 替换原代码
    const beforeLines = lines.slice(0, startLine)
    const afterLines = lines.slice(endLine + 1)
    
    // 生成调用代码
    const callCode = `${functionName}(${params.join(', ')});`
    
    return [...beforeLines, callCode, ...afterLines, '', newFunction].join('\n')
  }

  // 分析参数
  private analyzeParameters(code: string): string[] {
    // 简化的参数分析
    const variableRegex = /\b(let|const|var)\s+(\w+)/g
    const variables: string[] = []
    let match
    
    while ((match = variableRegex.exec(code)) !== null) {
      variables.push(match[2])
    }
    
    return variables
  }

  // 内联函数
  inlineFunction(functionName: string): string {
    const functionRegex = new RegExp(`function\\s+${functionName}\\s*\\([^)]*\\)\\s*\\{([^}]*)\\}`, 'g')
    const match = functionRegex.exec(this.code)
    
    if (!match) {
      return this.code
    }
    
    const functionBody = match[1].trim()
    
    // 替换所有调用
    const callRegex = new RegExp(`${functionName}\\s*\\([^)]*\\)\\s*;?`, 'g')
    return this.code.replace(callRegex, functionBody)
  }

  // 移动函数
  moveFunction(functionName: string, targetClass: string): string {
    // 找到函数定义
    const functionRegex = new RegExp(`(async\\s+)?function\\s+${functionName}\\s*\\([^)]*\\)\\s*\\{[^}]*\\}`, 'g')
    const match = functionRegex.exec(this.code)
    
    if (!match) {
      return this.code
    }
    
    const functionCode = match[0]
    
    // 从原类中移除
    let newCode = this.code.replace(functionCode, '')
    
    // 添加到目标类
    const classRegex = new RegExp(`(class\\s+${targetClass}\\s*\\{)`)
    newCode = newCode.replace(classRegex, `$1\n  ${functionCode}`)
    
    return newCode
  }

  // 提取类
  extractClass(className: string, properties: string[], methods: string[]): string {
    // 生成新类
    const classCode = `class ${className} {\n` +
      properties.map(p => `  ${p};`).join('\n') + '\n' +
      methods.map(m => `  ${m}() {}`).join('\n') + '\n' +
      `}`
    
    return this.code + '\n\n' + classCode
  }

  // 引入参数对象
  introduceParameterObject(functionName: string, paramNames: string[], objectName: string): string {
    const functionRegex = new RegExp(`(async\\s+)?function\\s+${functionName}\\s*\\(([^)]*)\\)`)
    const match = functionRegex.exec(this.code)
    
    if (!match) {
      return this.code
    }
    
    const params = match[2].split(',').map(p => p.trim())
    const objectParam = `{ ${paramNames.join(', ')} }`
    const newParams = params.filter(p => !paramNames.includes(p)).concat([objectParam])
    
    return this.code.replace(functionRegex, `function ${functionName}(${newParams.join(', ')})`)
  }
}

四、设计模式应用

4.1 常用设计模式

在这里插入图片描述

图3:设计模式——单例、工厂、观察者、策略、装饰器、适配器

设计模式描述适用场景优点缺点
单例模式确保只有一个实例全局配置节省资源难以测试
工厂模式创建对象的工厂对象创建复杂解耦创建与使用增加复杂度
观察者模式订阅-通知机制事件处理松耦合内存泄漏风险
策略模式封装算法族算法替换可扩展类数量增加
装饰器模式动态添加功能功能扩展灵活组合嵌套复杂
适配器模式接口转换兼容旧接口复用旧代码增加间接层

4.2 设计模式实现

// 单例模式
class Singleton {
  private static instance: Singleton
  private data: any

  private constructor() {
    this.data = {}
  }

  static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton()
    }
    return Singleton.instance
  }

  setData(key: string, value: any): void {
    this.data[key] = value
  }

  getData(key: string): any {
    return this.data[key]
  }
}

// 工厂模式
interface Product {
  name: string
  operation(): void
}

class ConcreteProductA implements Product {
  name = 'ProductA'
  
  operation(): void {
    console.log('ProductA operation')
  }
}

class ConcreteProductB implements Product {
  name = 'ProductB'
  
  operation(): void {
    console.log('ProductB operation')
  }
}

class ProductFactory {
  createProduct(type: string): Product {
    switch (type) {
      case 'A':
        return new ConcreteProductA()
      case 'B':
        return new ConcreteProductB()
      default:
        throw new Error(`Unknown product type: ${type}`)
    }
  }
}

// 观察者模式
interface Observer {
  update(data: any): void
}

class Subject {
  private observers: Observer[] = []
  private state: any

  addObserver(observer: Observer): void {
    this.observers.push(observer)
  }

  removeObserver(observer: Observer): void {
    const index = this.observers.indexOf(observer)
    if (index > -1) {
      this.observers.splice(index, 1)
    }
  }

  setState(state: any): void {
    this.state = state
    this.notify()
  }

  private notify(): void {
    for (const observer of this.observers) {
      observer.update(this.state)
    }
  }
}

// 策略模式
interface Strategy {
  execute(data: any): any
}

class ConcreteStrategyA implements Strategy {
  execute(data: any): any {
    return data.sort((a: number, b: number) => a - b)
  }
}

class ConcreteStrategyB implements Strategy {
  execute(data: any): any {
    return data.sort((a: number, b: number) => b - a)
  }
}

class Context {
  private strategy: Strategy

  setStrategy(strategy: Strategy): void {
    this.strategy = strategy
  }

  executeStrategy(data: any): any {
    return this.strategy.execute(data)
  }
}

五、自动化重构工具

5.1 DevEco Studio重构工具

在这里插入图片描述

图4:重构工具——重命名、提取方法、内联、移动、提取接口、提取超类

工具功能描述快捷键适用场景
重命名重命名标识符F2命名不规范
提取方法提取代码为方法Ctrl+Alt+M过长函数
内联内联变量或方法Ctrl+Alt+N过度抽象
移动移动类或方法F6职责不当
提取接口提取接口Ctrl+Alt+I需要多态
提取超类提取超类Ctrl+Alt+S代码复用

5.2 自动化重构实现

// 自动化重构工具
class AutomatedRefactoringTool {
  private code: string

  constructor(code: string) {
    this.code = code
  }

  // 自动重构
  autoRefactor(): string {
    let refactoredCode = this.code
    
    // 1. 提取过长函数
    refactoredCode = this.extractLongFunctions(refactoredCode)
    
    // 2. 内联简单函数
    refactoredCode = this.inlineSimpleFunctions(refactoredCode)
    
    // 3. 移动函数到合适的类
    refactoredCode = this.moveFunctionsToAppropriateClasses(refactoredCode)
    
    // 4. 提取重复代码
    refactoredCode = this.extractDuplicateCode(refactoredCode)
    
    // 5. 引入参数对象
    refactoredCode = this.introduceParameterObjects(refactoredCode)
    
    return refactoredCode
  }

  // 提取过长函数
  private extractLongFunctions(code: string): string {
    // 检测并提取过长函数
    const functionRegex = /(async\s+)?function\s+(\w+)\s*\([^)]*\)\s*\{([^}]*)\}/g
    let match
    let result = code
    
    while ((match = functionRegex.exec(code)) !== null) {
      const functionBody = match[3]
      const lines = functionBody.split('\n').length
      
      if (lines > 50) {
        // 提取函数的逻辑
        console.log(`Extracting long function: ${match[2]}`)
      }
    }
    
    return result
  }

  // 内联简单函数
  private inlineSimpleFunctions(code: string): string {
    // 检测并内联简单函数
    const functionRegex = /(async\s+)?function\s+(\w+)\s*\([^)]*\)\s*\{\s*return\s+([^;]+);\s*\}/g
    let match
    let result = code
    
    while ((match = functionRegex.exec(code)) !== null) {
      const functionName = match[2]
      const returnValue = match[3]
      
      // 内联函数的逻辑
      console.log(`Inlining simple function: ${functionName}`)
    }
    
    return result
  }

  // 移动函数到合适的类
  private moveFunctionsToAppropriateClasses(code: string): string {
    // 分析函数与类的关系,移动函数
    console.log('Moving functions to appropriate classes')
    return code
  }

  // 提取重复代码
  private extractDuplicateCode(code: string): string {
    // 检测并提取重复代码
    console.log('Extracting duplicate code')
    return code
  }

  // 引入参数对象
  private introduceParameterObjects(code: string): string {
    // 检测并引入参数对象
    console.log('Introducing parameter objects')
    return code
  }
}

六、重构实践

6.1 重构流程

在这里插入图片描述

图5:重构流程——识别坏味道 → 选择重构手法 → 执行重构 → 测试验证 → 提交代码

步骤描述工具注意事项
识别坏味道检测代码问题代码分析工具客观评估
选择手法确定重构策略重构目录小步前进
执行重构修改代码IDE重构工具保持行为不变
测试验证验证正确性单元测试确保无回归
提交代码版本控制Git清晰提交信息

6.2 重构实践示例

// 重构前
class OrderProcessor {
  processOrder(order: Order): void {
    // 验证订单
    if (!order.isValid()) {
      throw new Error('Invalid order')
    }
    
    // 计算价格
    let totalPrice = 0
    for (const item of order.items) {
      totalPrice += item.price * item.quantity
    }
    
    // 应用折扣
    if (order.customer.isVIP) {
      totalPrice *= 0.9
    }
    
    // 计算税费
    const tax = totalPrice * 0.1
    
    // 计算总价
    const finalPrice = totalPrice + tax
    
    // 保存订单
    order.totalPrice = finalPrice
    order.save()
    
    // 发送通知
    this.sendNotification(order.customer, `Order processed: $${finalPrice}`)
  }
  
  private sendNotification(customer: Customer, message: string): void {
    // 发送通知的实现
  }
}

// 重构后
class OrderProcessor {
  private priceCalculator: PriceCalculator
  private discountCalculator: DiscountCalculator
  private taxCalculator: TaxCalculator
  private notificationService: NotificationService

  constructor() {
    this.priceCalculator = new PriceCalculator()
    this.discountCalculator = new DiscountCalculator()
    this.taxCalculator = new TaxCalculator()
    this.notificationService = new NotificationService()
  }

  processOrder(order: Order): void {
    this.validateOrder(order)
    const totalPrice = this.calculateTotalPrice(order)
    const finalPrice = this.applyTax(totalPrice)
    
    this.saveOrder(order, finalPrice)
    this.notifyCustomer(order, finalPrice)
  }

  private validateOrder(order: Order): void {
    if (!order.isValid()) {
      throw new Error('Invalid order')
    }
  }

  private calculateTotalPrice(order: Order): number {
    const basePrice = this.priceCalculator.calculate(order.items)
    const discountedPrice = this.discountCalculator.applyDiscount(basePrice, order.customer)
    return discountedPrice
  }

  private applyTax(price: number): number {
    return this.taxCalculator.calculateTotal(price)
  }

  private saveOrder(order: Order, finalPrice: number): void {
    order.totalPrice = finalPrice
    order.save()
  }

  private notifyCustomer(order: Order, finalPrice: number): void {
    this.notificationService.send(order.customer, `Order processed: $${finalPrice}`)
  }
}

// 价格计算器
class PriceCalculator {
  calculate(items: OrderItem[]): number {
    return items.reduce((total, item) => total + item.price * item.quantity, 0)
  }
}

// 折扣计算器
class DiscountCalculator {
  applyDiscount(price: number, customer: Customer): number {
    return customer.isVIP ? price * 0.9 : price
  }
}

// 税费计算器
class TaxCalculator {
  calculateTotal(price: number): number {
    return price + price * 0.1
  }
}

// 通知服务
class NotificationService {
  send(customer: Customer, message: string): void {
    // 发送通知的实现
  }
}

七、常见问题与解决

问题现象原因解决方案
重构引入Bug重构后功能异常测试不足先写测试、小步重构
重构范围过大影响面广、风险高贪多求全小步前进、逐步重构
团队抵触不愿意重构缺乏认识培训、建立规范
时间压力没有重构时间项目紧张预留重构时间
重构过度过度设计追求完美适可而止
缺乏测试无法验证正确性测试覆盖低提高测试覆盖

八、结语:代码重构是持续改进的"阶梯"

代码重构是持续改进的"阶梯":

  • 识别坏味道:发现代码问题
  • 选择手法:确定重构策略
  • 执行重构:改善代码结构
  • 测试验证:确保正确性
  • 持续改进:保持代码质量

作为一名讲师,我在课上常说:**"代码重构不是一次性的工作,而是持续的过程。"**


转载自:https://blog.csdn.net/u014727709/article/details/166788414
欢迎 👍点赞✍评论⭐收藏,欢迎指正

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐