Kotlin遗留代码重构:策略与示例
处理遗留代码是每位开发者生活中不可避免的一部分。这类代码通常是用Java编写的,但即使是早期版本的Kotlin项目也可能包含代码坏味和架构错误。本文将详细讲解Kotlin遗留代码的分步重构策略,提供具体的转换示例,并介绍如何避免典型错误。
1. 重构准备:安全第一
第一步也是最重要的一步是确保变更的安全性。没有良好的测试覆盖,任何重构都会变成一场俄罗斯轮盘赌。
- 添加单元测试。如果没有测试,请为关键代码段编写测试。对于Kotlin,使用
JUnit 5和MockK框架。 - 固定行为。编写验证系统当前行为的测试(表征测试),即使它看起来不正确。这可以确保重构时不会破坏逻辑。
- 使用版本控制系统。在每个逻辑上完整的步骤之后进行提交,以便可以回滚。
Kotlin遗留函数的一个简单测试示例:
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class LegacyServiceTest {
@Test
fun `test calculateTotal`() {
val service = LegacyService()
val result = service.calculateTotal(listOf(10.0, 20.0, 30.0))
assertEquals(60.0, result)
}
}
2. 从Java逐步迁移到Kotlin
如果您的遗留代码是用Java编写的,不要试图一次性重写所有内容。使用自动转换器(例如IntelliJ IDEA内置的:Code → Convert Java File to Kotlin File),然后手动改进结果。
转换后需要注意的主要点:
- Null安全。将
@Nullable和@NonNull替换为?和!!运算符(仅在确定没有null时使用后者)。 - 数据类。使用
data class代替带有equals()和hashCode()的Java类。 - 扩展函数。将工具静态方法提取到扩展函数中。
Java类转换为Kotlin的示例:
// Java
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
// Kotlin (重构后)
data class User(val name: String, val age: Int)
3. 改进架构:摆脱意大利面条式代码
遗留代码常常违反SOLID原则。以下是三个有助于整理代码的具体技巧:
3.1. 职责分离
找到那些做得太多的类。例如,既存储数据、又进行验证、还发送请求的“上帝对象”。将其拆分为多个职责明确的类。
3.2. 将长if-else链替换为when
Kotlin提供了强大的when运算符,使代码更具可读性:
// 重构前
fun getStatusText(status: Int): String {
if (status == 0) return "Pending"
else if (status == 1) return "Active"
else if (status == 2) return "Blocked"
else return "Unknown"
}
// 重构后
fun getStatusText(status: Int): String = when (status) {
0 -> "Pending"
1 -> "Active"
2 -> "Blocked"
else -> "Unknown"
}