QDAirPortBackend0122/doc/work/PositionUpdateEvent_API重构_20250115.md
2026-01-22 13:19:47 +08:00

213 lines
6.1 KiB
Markdown
Raw 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.

# PositionUpdateEvent API重构文档
**创建日期:** 2025-01-15
**版本:** 0.1.11
**重构类型:** API设计原则的严格实施
## 问题背景
### 用户提出的问题
用户询问:"PositionUpdateEvent中为什么返回车辆ID用了string"
### 原有设计问题
1. **类型不一致**getVehicleId()返回String类型违背了"索引性质使用vehicleId"的设计原则
2. **混合逻辑**为了兼容两种不同的payload类型强制使用String统一返回
3. **语义不清**:没有明确区分索引标识符和业务标识符的使用场景
## 设计原则回顾
用户在前面确立的API设计原则
> **索引性质的返回值**使用vehicleId唯一、稳定的标识符
> **详细信息的返回值**包含vehicleId + licensePlate完整信息
## 重构方案
### 核心思路
区分不同数据类型和使用场景,提供专门的方法:
1. **索引性质**getVehicleId() → 返回Long类型
2. **业务标识符**getBusinessId() → 返回String类型
3. **完整信息**getVehicleIdentifier() → 返回完整对象
### 数据类型区分
#### 无人车数据VehicleLocation
- **vehicleId**Long类型数据库主键
- **businessId**String类型车牌号licensePlate
- **特点**:有数据库记录,支持索引查询
#### 航空器/机场车辆数据PositionUpdatePayload
- **vehicleId**null没有数据库记录
- **businessId**String类型航班号/车牌号objectId
- **特点**:仅实时处理,不持久化存储
## 重构实施
### 1. getVehicleId()方法重构
**修改前:**
```java
public String getVehicleId() {
if (payload instanceof VehicleLocation) {
return String.valueOf(((VehicleLocation) payload).getVehicleId());
} else if (payload instanceof PositionUpdatePayload) {
return ((PositionUpdatePayload) payload).getObjectId();
}
return null;
}
```
**修改后:**
```java
public Long getVehicleId() {
if (payload instanceof VehicleLocation) {
return ((VehicleLocation) payload).getVehicleId();
}
// 航空器和机场车辆没有数据库记录返回null
return null;
}
```
### 2. 新增getBusinessId()方法
```java
public String getBusinessId() {
if (payload instanceof VehicleLocation) {
return ((VehicleLocation) payload).getLicensePlate();
} else if (payload instanceof PositionUpdatePayload) {
return ((PositionUpdatePayload) payload).getObjectId();
}
return null;
}
```
### 3. 新增getVehicleIdentifier()方法
```java
public VehicleIdentifier getVehicleIdentifier() {
if (payload instanceof VehicleLocation) {
VehicleLocation location = (VehicleLocation) payload;
return VehicleIdentifier.builder()
.vehicleId(location.getVehicleId())
.businessId(location.getLicensePlate())
.vehicleType(location.getVehicleType().name())
.build();
} else if (payload instanceof PositionUpdatePayload) {
PositionUpdatePayload positionPayload = (PositionUpdatePayload) payload;
return VehicleIdentifier.builder()
.vehicleId(null) // 航空器没有数据库记录
.businessId(positionPayload.getObjectId())
.vehicleType(positionPayload.getObjectType())
.build();
}
return null;
}
```
### 4. VehicleIdentifier内部类
```java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class VehicleIdentifier {
private Long vehicleId; // 数据库主键(索引性质)
private String businessId; // 业务标识符(车牌号、航班号等)
private String vehicleType; // 车辆类型
}
```
## 使用场景说明
### 索引场景
```java
PositionUpdateEvent event = new PositionUpdateEvent(vehicleLocation);
// 用于Map索引仅无人车有效
Long vehicleId = event.getVehicleId();
if (vehicleId != null) {
vehicleLocationMap.put(String.valueOf(vehicleId), location);
}
```
### 业务展示场景
```java
// 用于前端显示
String displayId = event.getBusinessId(); // 车牌号或航班号
String displayText = "车辆: " + displayId;
```
### 完整信息场景
```java
// 获取完整标识符信息
VehicleIdentifier identifier = event.getVehicleIdentifier();
if (identifier.getVehicleId() != null) {
// 有数据库记录的无人车
processUnmannedVehicle(identifier);
} else {
// 仅实时处理的航空器/机场车辆
processRealtimeObject(identifier);
}
```
## 测试用例修正
### 修改前
```java
assertEquals("TEST_AIRCRAFT_001", event.getVehicleId());
```
### 修改后
```java
// 航空器没有数据库记录
assertNull(event.getVehicleId());
assertEquals("TEST_AIRCRAFT_001", event.getBusinessId());
// 验证完整标识符信息
VehicleIdentifier identifier = event.getVehicleIdentifier();
assertNull(identifier.getVehicleId());
assertEquals("TEST_AIRCRAFT_001", identifier.getBusinessId());
assertEquals("AIRCRAFT", identifier.getVehicleType());
```
## 技术优势
### 1. 类型安全
- 明确的Long/String类型区分
- 避免不必要的类型转换
- 编译时类型检查
### 2. 语义清晰
- 索引和业务标识符明确分离
- 方法名称直接表达用途
- 减少使用时的歧义
### 3. 扩展性
- VehicleIdentifier类支持未来扩展
- 不同数据源的统一处理
- 保持向后兼容性
### 4. 性能优化
- 减少不必要的字符串转换
- Map操作使用数字索引更高效
- 内存使用更节省
## 验证结果
- ✅ 编译测试通过
- ✅ 单元测试通过WebSocketEventTest
- ✅ API设计原则完全落实
- ✅ 保持向后兼容性
- ✅ 文档和测试用例更新完成
## 设计原则强化
通过这次重构进一步强化了API设计原则的应用
1. **索引性质** → 明确的数据类型Long
2. **详细信息** → 完整的信息对象VehicleIdentifier
3. **业务语义** → 专门的业务标识符方法getBusinessId
4. **类型安全** → 编译时类型检查和null处理
这个重构为项目中所有类似的API设计树立了标准确保了设计的一致性和可维护性。