6.9 KiB
6.9 KiB
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中清除实例字段、只 UnregisterISaveableRegistryGameManager新增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:
// 新增(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 拖慢场景打开