多轮审查和修复
This commit is contained in:
174
Docs/Review/FrameworkReview_2026_May_v3.md
Normal file
174
Docs/Review/FrameworkReview_2026_May_v3.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# 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<SaveManager>()` 直接访问,绕过接口层。
|
||||
|
||||
**根因**:`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<ISaveService>()`。
|
||||
|
||||
**状态**:✅ 已修复
|
||||
|
||||
---
|
||||
|
||||
### B-2(高)`SaveManager` / `GameManager` 以具体类型自注册到 ServiceLocator
|
||||
|
||||
**问题**:
|
||||
- `SaveManager.Awake()`:`ServiceLocator.Register<SaveManager>(this)` 仅用于自身重复防护
|
||||
- `GameManager.Awake()`:`ServiceLocator.Register<GameManager>(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<string> 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>()` | 仅为开发示例注释,不影响运行 |
|
||||
| `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 拖慢场景打开
|
||||
Reference in New Issue
Block a user