【共创稿事节】DevEco Studio代码重构:从坏味道到设计模式
新星共创者
·
文章目录

每日一句正能量
主动选择,接纳周期
有些路你必须一个人走,这不是孤独,而是选择。
相信"代码重构是持续改进的阶梯"。
摘要
摘要:代码重构是提升代码质量的重要手段。本文深入探讨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
欢迎 👍点赞✍评论⭐收藏,欢迎指正
更多推荐


所有评论(0)