362 lines
12 KiB
Markdown
362 lines
12 KiB
Markdown
# 代码重构前后对比
|
||
|
||
## 整体改进
|
||
|
||
### 原项目问题
|
||
```
|
||
❌ 每次调用都重新创建对象(浪费资源,状态丢失)
|
||
❌ 流程不清晰,难以扩展
|
||
❌ 职责混乱,不知道在哪里插入新功能
|
||
❌ 数据模型不完整(缺少中间状态的定义)
|
||
❌ 无法直观看出数据在各步骤间如何流动
|
||
```
|
||
|
||
### 改进后的特点
|
||
```
|
||
✅ 对象复用(一次初始化,重复使用)
|
||
✅ 清晰的4步数据流(每步职责明确)
|
||
✅ 易于扩展(预留位置清楚标记)
|
||
✅ 完整的数据模型(每步都有输出定义)
|
||
✅ 充分的注释和伪代码(易于理解和修改)
|
||
```
|
||
|
||
## 具体对比
|
||
|
||
### 对比1:主程序入口
|
||
|
||
#### 原代码 (Main.kt)
|
||
```kotlin
|
||
fun main() {
|
||
} // 空的,什么都没有
|
||
```
|
||
|
||
#### 新代码 (Main.kt)
|
||
```kotlin
|
||
fun main() {
|
||
// 1. 加载样本轨迹
|
||
val route = sampleRoute
|
||
|
||
// 2. 创建模拟器(只创建一次)
|
||
val simulator = TrajectorySimulator(route)
|
||
|
||
// 3. 配置参数
|
||
simulator.setPhysicsParams(...)
|
||
simulator.setNoiseParams(...)
|
||
|
||
// 4. 模拟循环(逐时间步调用)
|
||
for (time in 0.0..duration step 0.1) {
|
||
val motionState = simulator.simulate(time)
|
||
println(motionState)
|
||
}
|
||
}
|
||
```
|
||
|
||
**改进**:清晰展示了如何使用,每个步骤有注释说明
|
||
|
||
---
|
||
|
||
### 对比2:主处理流程
|
||
|
||
#### 原代码 (Runner.getCoordinate)
|
||
```kotlin
|
||
class Runner(val route: List<MetaCoordinate>) {
|
||
fun getCoordinate(time: Double): Coordinate {
|
||
val path = PathLinearize(route) // ❌ 每次都创建
|
||
val physicEngine = RunnerPhysic() // ❌ 每次都创建
|
||
val noiseEngine = PathNoiseEngine() // ❌ 每次都创建
|
||
|
||
val distance = physicEngine.getDistance(time)
|
||
val coordinate = path.getPointDistance(distance)
|
||
val finalCoordinate = noiseEngine.applyNoise(coordinate.lat, coordinate.lon, physicEngine)
|
||
|
||
return finalCoordinate
|
||
}
|
||
}
|
||
```
|
||
|
||
**问题**:
|
||
- 每次都重新创建对象,浪费资源
|
||
- NoiseEngine 中的漂移状态会丢失
|
||
- 流程混乱,无法清晰看出数据如何流转
|
||
- 返回值类型混乱(Coordinate vs 其他)
|
||
|
||
#### 新代码 (TrajectorySimulator.simulate)
|
||
```kotlin
|
||
class TrajectorySimulator(route: List<MetaCoordinate>) {
|
||
// 一次初始化,重复使用
|
||
private val pathInterpolator: PathInterpolator = PathInterpolator(route)
|
||
private val physicsEngine: RunnerPhysics = RunnerPhysics()
|
||
private val noiseProcessor: NoiseProcessor = NoiseProcessor()
|
||
|
||
fun simulate(time: Double): MotionState {
|
||
// ════════════════════════════════════════════
|
||
// 步骤1:计算物理状态
|
||
// ════════════════════════════════════════════
|
||
val physicsState = physicsEngine.calculate(time) // ✅ 返回 PhysicsState
|
||
|
||
// ════════════════════════════════════════════
|
||
// 步骤2:路径插值
|
||
// ════════════════════════════════════════════
|
||
val rawCoordinate = pathInterpolator.interpolate(physicsState.distance) // ✅ 返回 RawCoordinate
|
||
|
||
// ════════════════════════════════════════════
|
||
// 步骤3:添加噪声
|
||
// ════════════════════════════════════════════
|
||
val noisyCoordinate = noiseProcessor.applyNoise(rawCoordinate, physicsState) // ✅ 返回 NoisyCoordinate
|
||
|
||
// ════════════════════════════════════════════
|
||
// 步骤4:组装最终状态
|
||
// ════════════════════════════════════════════
|
||
return MotionState(...) // ✅ 返回完整的 MotionState
|
||
}
|
||
}
|
||
```
|
||
|
||
**改进**:
|
||
- 对象复用,提高效率
|
||
- 4步流程清晰,每步职责明确
|
||
- 每步都有明确的输入输出类型
|
||
- 易于理解和调试
|
||
|
||
---
|
||
|
||
### 对比3:坐标数据模型
|
||
|
||
#### 原代码
|
||
```kotlin
|
||
// 只有两个坐标类,中间状态混乱
|
||
data class Coordinate(val lon: Double, val lat: Double, val time: Double)
|
||
data class MetaCoordinate(val lon: Double, val lat: Double)
|
||
```
|
||
|
||
#### 新代码
|
||
```kotlin
|
||
// 完整的数据流定义
|
||
data class MetaCoordinate(val lon: Double, val lat: Double) // 原始轨迹点
|
||
|
||
data class RawCoordinate(val lon: Double, val lat: Double) // 无噪声插值点
|
||
|
||
data class NoisyCoordinate(
|
||
val lon: Double,
|
||
val lat: Double,
|
||
val gpsError: Double // 记录噪声大小
|
||
)
|
||
|
||
data class Coordinate(val lon: Double, val lat: Double, val time: Double) // 带时间的坐标
|
||
```
|
||
|
||
**改进**:
|
||
- 每个数据流阶段都有明确的数据类型
|
||
- 便于调试和理解数据的变换过程
|
||
- 预留了噪声信息的记录
|
||
|
||
---
|
||
|
||
### 对比4:物理引擎
|
||
|
||
#### 原代码
|
||
```kotlin
|
||
class RunnerPhysic {
|
||
fun getDistance(time: Double): Double {} // ❌ 未实现,空的
|
||
}
|
||
```
|
||
|
||
#### 新代码
|
||
```kotlin
|
||
class RunnerPhysics(
|
||
private val totalDistance: Double = 0.0,
|
||
private val duration: Double = 1000.0,
|
||
private val maxVelocity: Double = 4.0
|
||
) {
|
||
/**
|
||
* 计算指定时间的物理状态
|
||
*
|
||
* @param time 当前时间(秒)
|
||
* @return 包含距离、速度、加速度的物理状态
|
||
*/
|
||
fun calculate(time: Double): PhysicsState {
|
||
// 伪代码说明:
|
||
// 1. 计算距离
|
||
// 2. 计算速度
|
||
// 3. 计算加速度
|
||
|
||
val distance = getDistance(time)
|
||
val velocity = 0.0 // TODO: 实现
|
||
val acceleration = 0.0 // TODO: 实现
|
||
|
||
return PhysicsState(time, distance, velocity, acceleration)
|
||
}
|
||
|
||
fun getDistance(time: Double): Double {
|
||
// 伪代码说明
|
||
return 0.0 // TODO: 实现
|
||
}
|
||
}
|
||
```
|
||
|
||
**改进**:
|
||
- 返回类型改为 PhysicsState(包含完整的物理信息)
|
||
- 添加了伪代码说明实现思路
|
||
- 添加了TODO标记,清楚地标出需要实现的地方
|
||
- 参数化了初始值(便于配置)
|
||
|
||
---
|
||
|
||
### 对比5:路径插值器
|
||
|
||
#### 原代码 (pathLinearlizer.kt)
|
||
```kotlin
|
||
class PathLinearize(val nodes: List<MetaCoordinate>) {
|
||
private val segments = nodes.windowed(2).map { (a, b) ->
|
||
val distance = haversine(a, b)
|
||
Triple(a, b, distance)
|
||
}
|
||
|
||
fun haversine(node1: MetaCoordinate, node2: MetaCoordinate): Double {
|
||
// ... 完整的Haversine算法(逻辑保留)
|
||
}
|
||
|
||
fun getPointDistance(totalDistance: Double): MetaCoordinate {
|
||
// ... 插值逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 新代码 (PathInterpolator.kt)
|
||
```kotlin
|
||
class PathInterpolator(val nodes: List<MetaCoordinate>) {
|
||
private val segments = nodes.windowed(2).map { (a, b) ->
|
||
val distance = calculateHaversineDistance(a, b) // ✅ 改名:更清晰
|
||
Triple(a, b, distance)
|
||
}
|
||
|
||
fun interpolate(totalDistance: Double): RawCoordinate { // ✅ 改名:更直观
|
||
// ... 同样的插值逻辑,完全保留
|
||
}
|
||
|
||
private fun calculateHaversineDistance(node1: MetaCoordinate, node2: MetaCoordinate): Double {
|
||
// ✅ Haversine逻辑完全保留,只改了方法名
|
||
// 和原代码一模一样
|
||
}
|
||
}
|
||
```
|
||
|
||
**改进**:
|
||
- 类名改为 PathInterpolator(更准确)
|
||
- 方法名改为 `interpolate` 和 `calculateHaversineDistance`(更清晰)
|
||
- 返回类型改为 RawCoordinate(更明确)
|
||
- **核心逻辑完全保留**,只改了命名
|
||
|
||
---
|
||
|
||
### 对比6:噪声处理
|
||
|
||
#### 原代码
|
||
```kotlin
|
||
class PathNoiseEngine(
|
||
private val gpsErrorStdDev: Double = 0.00002,
|
||
private val driftWeight: Double = 0.3
|
||
) {
|
||
private val random = Random()
|
||
private var driftLat = 0.0
|
||
private var driftLon = 0.0
|
||
|
||
fun applyNoise(rawLat: Double, rawLon: Double, physic: RunnerPhysic): Coordinate {
|
||
// ... 白噪声和漂移逻辑(完全保留)
|
||
return Coordinate(rawLon+whiteNoiseLon+driftLon, rawLat+whiteNoiseLat+driftLat, time = Double)
|
||
// ❌ time = Double 是个错误,应该是实际时间值
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 新代码 (GpsNoiseEngine.kt)
|
||
```kotlin
|
||
class GpsNoiseEngine(
|
||
private val gpsErrorStdDev: Double = 0.00002,
|
||
private val driftWeight: Double = 0.3
|
||
) {
|
||
/**
|
||
* 应用GPS噪声到坐标
|
||
*
|
||
* 伪代码:
|
||
* 1. 生成白噪声
|
||
* 2. 生成漂移
|
||
* 3. 合并噪声
|
||
*/
|
||
fun applyNoise(
|
||
rawLon: Double,
|
||
rawLat: Double,
|
||
physicsState: PhysicsState
|
||
): Triple<Double, Double, Double> { // ✅ 更清晰的返回类型
|
||
|
||
// 第1步:白噪声(逻辑完全保留)
|
||
val whiteNoiseLat = random.nextGaussian() * gpsErrorStdDev
|
||
val whiteNoiseLon = random.nextGaussian() * gpsErrorStdDev
|
||
|
||
// 第2步:漂移(逻辑完全保留)
|
||
driftLat = driftLat * 0.8 + random.nextGaussian() * gpsErrorStdDev * driftWeight
|
||
driftLon = driftLon * 0.8 + random.nextGaussian() * gpsErrorStdDev * driftWeight
|
||
|
||
// 第3步:合并(逻辑完全保留)
|
||
val finalLon = rawLon + whiteNoiseLon + driftLon
|
||
val finalLat = rawLat + whiteNoiseLat + driftLat
|
||
|
||
val totalError = sqrt((whiteNoiseLon + driftLon).pow(2) + (whiteNoiseLat + driftLat).pow(2))
|
||
|
||
return Triple(finalLon, finalLat, totalError) // ✅ 返回噪声大小便于记录
|
||
}
|
||
}
|
||
```
|
||
|
||
新增 NoiseProcessor(协调多个噪声引擎):
|
||
```kotlin
|
||
class NoiseProcessor {
|
||
private val gpsNoiseEngine = GpsNoiseEngine()
|
||
// 预留位置:
|
||
// private val velocityNoiseEngine = VelocityNoiseEngine()
|
||
// private val accelerationNoiseEngine = AccelerationNoiseEngine()
|
||
|
||
fun applyNoise(rawCoord: RawCoordinate, physicsState: PhysicsState): NoisyCoordinate {
|
||
val (noisyLon, noisyLat, gpsError) = gpsNoiseEngine.applyNoise(
|
||
rawCoord.lon, rawCoord.lat, physicsState
|
||
)
|
||
|
||
// ✅ 预留位置:
|
||
// val velocityNoise = velocityNoiseEngine.applyNoise(physicsState.velocity)
|
||
// val accelNoise = accelerationNoiseEngine.applyNoise(physicsState.acceleration)
|
||
|
||
return NoisyCoordinate(noisyLon, noisyLat, gpsError)
|
||
}
|
||
}
|
||
```
|
||
|
||
**改进**:
|
||
- 返回值更明确(Triple 包含噪声大小)
|
||
- 创建 NoiseProcessor 协调多个噪声引擎
|
||
- **GPS噪声算法逻辑完全保留**
|
||
- 清晰标记了预留位置供未来扩展
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
| 方面 | 原代码 | 新代码 |
|
||
|------|--------|--------|
|
||
| **项目独立性** | 修改原项目 | 新建独立项目,原项目不动 |
|
||
| **对象管理** | 每次重建 | 一次初始化,重复使用 |
|
||
| **流程清晰度** | 混乱 | 4步清晰流程 |
|
||
| **数据模型** | 不完整 | 完整的中间状态定义 |
|
||
| **命名规范** | 不规范 | 规范统一 |
|
||
| **注释文档** | 无 | 充分的伪代码和说明 |
|
||
| **扩展预留** | 无 | 清晰标记的预留位置 |
|
||
| **核心算法** | 保留 | **完全保留** |
|
||
|
||
---
|
||
|
||
## 如何使用新项目
|
||
|
||
1. **快速上手**:看 Main.kt(完整使用示例)
|
||
2. **理解流程**:看 DATA_FLOW_GUIDE.md(数据流参考)
|
||
3. **要修改代码**:看 README.md(各文件职责说明)
|
||
4. **要加新功能**:看 GpsNoiseEngine.kt(预留位置已标记)
|