JavaProjectRepo/business-css/SimController 及相关接口实现建议v4.md
2026-03-19 11:18:15 +08:00

6.7 KiB
Raw Blame History

SimController 及相关接口实现建议 v4

基于 情景模拟分析结果v3.md 中的分析,SimController 及其配套组件 (SimService, SimBuilder, SimModel) 代表了系统向模块化、可测试化方向演进的正确路径。

当前 SimController 处于不可用状态(依赖缺失、逻辑简化、代码注释)。为了将其转化为生产可用的仿真服务,以下是具体的实现建议与重构方案。


1. 总体架构设计

目标是将仿真逻辑从 ProjectServiceImpl 中剥离,构建独立的仿真层。

  • Controller 层 (SimController): 仅负责接收 HTTP 请求,参数校验,调用 Service返回结果。
  • Facade 层 (SimDataFacade): 新增组件。负责与现有的 ProjectService, EventService, InfluenceService 交互获取原始数据Project 实体, Event 列表等),并屏蔽数据库细节。注:原设计中的 ProjectRepository 等接口在本项目中没有实现,直接复用现有的 Service 层更符合现状。
  • Builder 层 (SimBuilder): 负责将原始数据Entity/JSON转换为仿真专用的领域模型 (SimUnit, SimEvent, SimInfluenceNode)。
  • Engine 层 (SimService): 核心计算引擎。纯内存计算,不依赖数据库。执行 Static -> Event -> Influence -> Override 的标准管线。

2. 详细实现建议

2.1 补齐数据获取层 (SimDataFacade)

SimController 依赖了不存在的 ProjectRepository 等接口。建议创建一个 SimDataFacade 来封装数据获取逻辑。

@Component
public class SimDataFacade {
    private final ProjectService projectService;
    private final EventService eventService;
    // ... 其他 Service

    // 封装获取逻辑:获取项目拓扑、事件列表、影响关系等
    public SimDataPackage loadSimulationData(String projectId, String scenarioId) {
        Project project = projectService.getById(projectId);
        List<Event> events = eventService.list(new QueryWrapper<Event>().eq("scenario_id", scenarioId));
        // ... 获取其他必要数据
        return new SimDataPackage(project, events);
    }
}

2.2 激活并增强 Builder (SimBuilder)

SimBuilder 目前被注释掉了,需要激活并实现核心转换逻辑。重点是将 ProjectServiceImpl.initSimulation 中的解析逻辑迁移过来。

  • buildUnits: 解析 Project.topology JSON提取 Device 和 Material构建 SimUnit 列表。
    • 关键点需要包含静态属性Static Values的解析作为 SimUnit 的初始状态。
  • buildEvents: 解析 Event.attr_changes JSON构建 SimEvent 列表。
    • 关键点:区分 普通事件 (Input)强制覆盖事件 (Override)。建议在 SimEvent 中增加 isOverride 标志。
  • buildInfluenceNodes: 解析 Project.topology 中的 properties -> influence 节点,构建 SimInfluenceNode 列表。

2.3 重构计算引擎 (SimService)

这是最核心的部分,必须修正当前的“事件 -> 计算”逻辑,改为 标准管线

建议代码结构:

public class SimService {

    public SimContext runSimulation(List<SimUnit> units, 
                                    List<SimEvent> events, 
                                    List<SimInfluenceNode> nodes, 
                                    int steps) {
        SimContext ctx = new SimContext();

        // 1. 初始化静态基线 (Static)
        // 将 SimUnit 中携带的静态属性写入 ctx (t=0)
        for (SimUnit unit : units) {
            unit.getStaticProperties().forEach((k, v) -> 
                ctx.setValue(SimPropertyKey.of(unit.id(), k), v)
            );
        }

        // 2. 时间步推进
        for (int step = 0; step <= steps; step++) {
            // 2.1 应用输入事件 (Event Input)
            // 筛选当前 step 的普通事件,写入 ctx
            applyEvents(ctx, events, step, false);

            // 2.2 执行影响计算 (Influence)
            // 基于当前 ctx 状态,计算所有 InfluenceNode
            // 注意:为了避免计算顺序依赖,建议使用双缓冲 (Snapshot) 或 拓扑排序
            // 简单实现可先计算 diff再统一应用
            applyInfluences(ctx, nodes);

            // 2.3 应用强制覆盖事件 (Event Override)
            // 筛选当前 step 的强制事件,再次写入 ctx覆盖计算结果
            applyEvents(ctx, events, step, true);

            // 2.4 保存快照
            ctx.snapshot(step);
        }
        return ctx;
    }
}

2.4 统一 API 接口 (SimController)

建议将 SimController 作为仿真功能的唯一入口。

@RestController
@RequestMapping("/sim")
public class SimController {

    @PostMapping("/run")
    public Result<SimulationResult> run(@RequestBody SimulationRequest req) {
        // 1. 加载数据
        SimDataPackage data = simDataFacade.loadSimulationData(req.getProjectId(), req.getScenarioId());
        
        // 2. 构建模型
        List<SimUnit> units = SimBuilder.buildUnits(data.getProject());
        List<SimEvent> events = SimBuilder.buildEvents(data.getEvents());
        List<SimInfluenceNode> nodes = SimBuilder.buildInfluenceNodes(data.getProject());
        
        // 3. 执行仿真
        SimContext ctx = simService.runSimulation(units, events, nodes, req.getSteps());
        
        // 4. 结果转换 (适配前端图表或 AI 推理)
        return Result.success(SimResultConverter.convert(ctx));
    }
}

3. 实施路线图

  1. 基础类准备:

    • 完善 SimUnit: 增加 Map<String, Double> staticProperties 字段。
    • 完善 SimEvent: 增加 boolean isOverride 字段。
    • 创建 SimDataFacade 类。
  2. 迁移解析逻辑:

    • ProjectServiceImpl 中解析 JSON (Topology, Event) 的代码块复制到 SimBuilder 中并适配。
    • 确保单元测试覆盖 SimBuilder,保证解析正确性。
  3. 实现计算逻辑:

    • 编写 SimService.runSimulation,严格按照推荐的 4 步管线实现。
    • 编写单元测试,验证“事件覆盖计算”和“计算基于静态值”的场景。
  4. 接口接入:

    • SimController 中装配上述组件。
    • 前端对接新的 /sim/run 接口。
  5. 清理:

    • 标记 ProjectServiceImpl 中的旧模拟代码为 @Deprecated,并在验证新接口无误后删除。

通过以上步骤,可以将复杂的仿真逻辑从业务 Service 中解耦,构建一个清晰、可维护、易扩展的仿真引擎。