likeRunner/BEFORE_AFTER.md
pythagodzilla 07cb1304d2 init
2026-03-19 17:57:03 +08:00

362 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 代码重构前后对比
## 整体改进
### 原项目问题
```
❌ 每次调用都重新创建对象(浪费资源,状态丢失)
❌ 流程不清晰,难以扩展
❌ 职责混乱,不知道在哪里插入新功能
❌ 数据模型不完整(缺少中间状态的定义)
❌ 无法直观看出数据在各步骤间如何流动
```
### 改进后的特点
```
✅ 对象复用(一次初始化,重复使用)
✅ 清晰的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预留位置已标记