# Framework Review — v3(2026 年 5 月) > **基准**:本文档在 v1(9 项)和 v2(7 项)全部修复完毕的基础上,对 `Assets/Scripts` 进行第三轮深度扫描。 > **验证**:修复完成后 `get_errors()` → No errors(零编译错误)。 --- ## 一、总体架构健康评估 ### ✅ 已通过验证的核心设计 | 检查项 | 结论 | |--------|------| | ServiceLocator 注册模式 | 所有注册均使用接口类型(含本轮新增)| | RAII 事件订阅模式 | `Subscribe().AddTo(_subs)` + `_subs.Clear()` 全覆盖 | | 无 FindObjectOfType | 全代码库零调用 | | 无 Singleton 滥用 | NullFeedbackPlayer.Instance 为合法 Null Object Pattern | | 事件频道 DDOL 隔离 | EventChannelRegistry 已修复(v1-M3)| | 存档完整性 | HMAC-SHA256 + 原子写入 | | 程序集依赖单向性 | Core → Core.Save 方向保持不变 | --- ## 二、本轮(v3)发现的问题 ### B-1(高)`SaveManager` 大量具体类型直接查询(8 个文件) **问题**:`ISaveService` 接口仅覆盖了 I/O 操作(Save/Load/QuickSave),`SaveManager` 的业务 查询 API(`GetFlag`、`IsBossDefeated`、`LastCheckpointScene` 等)被 8 个文件通过 `ServiceLocator.GetOrDefault()` 直接访问,绕过接口层。 **根因**:`BaseGames.Core.Save` 与 `BaseGames.Core` 存在单向依赖约束(Save 不引用 Core), 导致 `SaveManager` 无法直接实现 `ISaveService`;历史上 `SaveServiceAdapter` 仅转发了最小集合。 **受影响文件**: - `Quest/ChallengeRoomManager.cs`(QuickSave、IsFirstClear、QuickLoad) - `Quest/ChallengeRoomTrigger.cs`(IsBossDefeated) - `EventChain/EventChainSO.cs`(GetFlag、SetFlag) - `EventChain/EventChainManager.cs`(GetCompletedChains、SetChainCompleted) - `Progression/HPContainerPickup.cs`(IsWorldCollected、GetPlayerMaxHP) - `Progression/ProgressLock.cs`(IsBossDefeated、IsDoorOpened) - `Core/DeathRespawnService.cs`(LastCheckpointScene/SpawnId、DeleteSlotAsync、ActiveSlot) - `Support/AntiSoftlock/AntiSoftlockSystem.cs`(LastCheckpointScene/SpawnId) **修复方案**:扩展 `ISaveService` 接口覆盖所有业务查询方法;扩展 `SaveServiceAdapter` 完整转发;所有 8 个文件改用 `GetOrDefault()`。 **状态**:✅ 已修复 --- ### B-2(高)`SaveManager` / `GameManager` 以具体类型自注册到 ServiceLocator **问题**: - `SaveManager.Awake()`:`ServiceLocator.Register(this)` 仅用于自身重复防护 - `GameManager.Awake()`:`ServiceLocator.Register(this)` 仅用于自身重复防护 两者均无外部调用方通过接口以外的方式依赖该注册;具体类型暴露在 ServiceLocator 中违反 "通过接口而非实现依赖" 框架原则。 **修复方案**: - 两个类均改用 `private static T _instance;` 实例字段做重复防护 - `SaveManager.OnDestroy` 中清除实例字段、只 Unregister `ISaveableRegistry` - `GameManager` 新增 `OnDestroy` 清除实例字段 **状态**:✅ 已修复 --- ## 三、修复后的 ServiceLocator 全景(v3 快照) ### 注册表(Register) | 文件 | 接口键 | 说明 | |------|--------|------| | `GameServiceRegistrar.cs` | `IAudioService`(NullAudioService 兜底) | 框架启动兜底 | | `GameServiceRegistrar.cs` | `IDeathRespawnService` | Persistent 服务 | | `GameServiceRegistrar.cs` | `ISceneService` | Persistent 服务 | | `GameServiceRegistrar.cs` | `IEventChannelRegistry` | Persistent 服务 | | `GameServiceRegistrar.cs` | `ISaveService`(via SaveServiceAdapter) | Persistent 服务 | | `AudioManager.cs` | `IAudioService` | 覆盖兜底 | | `CameraStateController.cs` | `ICameraService` | | | `ClashResolver.cs` | `IClashService` | | | `DifficultyManager.cs` | `IDifficultyService` | | | `EventChannelRegistry.cs` | `IEventChannelRegistry` | | | `GlobalObjectPool.cs` | `IObjectPoolService` | | | `HitStopManager.cs` | `IHitStopService` | | | `LocalizationManager.cs` | `ILocalizationService` | | | `MapManager.cs` | `IMapService` | | | `ProjectileManager.cs` | `IProjectileService` | | | `QuestManager.cs` | `IQuestManager` | | | `SaveManager.cs` | `ISaveableRegistry` | | | `SettingsManager.cs` | `ISettingsService` | | | `TutorialManager.cs` | `ITutorialService` | | | `VFXPool.cs` | `IVFXPoolService` | | | `AchievementManager.cs` | `IAchievementService` | | | `AnalyticsManager.cs` | `IAnalyticsService` | | | `DialogueManager.cs` | `IDialogueService` | | | `PlatformBootstrap.cs` | `IPlatformService` | | > **全部使用接口类型键,无任何具体类型键残留。** --- ## 四、ISaveService 扩展内容(v3 新增) 本轮将 `ISaveService` 从 6 个成员扩展至 19 个成员,覆盖存档系统全部公开 API: ```csharp // 新增(v3) void QuickLoad(); // 同步 fire-and-forget 版 Task DeleteSlotAsync(int slot); string LastCheckpointScene { get; } string LastCheckpointSpawnId { get; } bool IsWorldCollected(string id); bool IsDoorOpened(string id); bool IsBossDefeated(string bossId); int GetPlayerMaxHP(); bool IsFirstClear(string challengeId); bool GetFlag(string flagId); void SetFlag(string flagId, bool value); IEnumerable GetCompletedChains(); void SetChainCompleted(string chainId); ``` `SaveServiceAdapter` 内部完整转发上述全部方法。 --- ## 五、三轮修复汇总 | 版本 | 问题数 | 类别 | 全部修复 | |------|--------|------|----------| | v1 | 9 | H×2, M×3, L×4 | ✅ | | v2 | 7 | A(架构)×7 | ✅ | | v3 | 2 | B(接口完整性)×2 | ✅ | | **总计** | **18** | | ✅ 零编译错误 | --- ## 六、已知可接受的模式(非问题) | 文件 | 模式 | 说明 | |------|------|------| | `FalseWall.cs:51` | 注释中的 `GetOrDefault()` | 仅为开发示例注释,不影响运行 | | `SaveManager.cs` 内部 `_instance` 字段 | `static SaveManager _instance` | 仅用于重复防护,无外部暴露 | | `GameManager.cs` 内部 `_instance` 字段 | `static GameManager _instance` | 同上 | --- ## 七、当前代码库整体评估 ### 架构设计 ⭐⭐⭐⭐⭐ - ServiceLocator 接口-实现分离完整 - 程序集依赖方向清晰(Core.Events ← Core.Save ← Core ← 业务模块) - SaveServiceAdapter 桥接模式正确解决跨程序集约束 ### 可维护性 ⭐⭐⭐⭐⭐ - 所有服务可独立 mock/替换 - 事件频道完全解耦 - 无 FindObjectOfType / Singleton 滥用 ### 扩展性 ⭐⭐⭐⭐ - 新服务只需:定义接口 → 实现类 → Awake 注册 - ISaveService 已覆盖全部存档操作,后续扩展追加方法即可 ### 性能 ⭐⭐⭐⭐ - ObjectPool 覆盖 Projectile/VFX/Minion - Update 热路径已缓存组件引用(v1/v2 已修复) - 存档 SemaphoreSlim 保证异步安全 ### 编辑器友好 ⭐⭐⭐⭐ - 全部服务引用通过 `[SerializeField]` 在 Inspector 绑定 - 无 FindObjectOfType 拖慢场景打开