Files
zeling_v2/Docs/Review/FrameworkReview_2026_May_v3.md
2026-05-12 15:34:08 +08:00

6.9 KiB
Raw Blame History

Framework Review — v32026 年 5 月)

基准:本文档在 v19 项)和 v27 项)全部修复完毕的基础上,对 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-1SaveManager 大量具体类型直接查询8 个文件)

问题ISaveService 接口仅覆盖了 I/O 操作Save/Load/QuickSaveSaveManager 的业务 查询 APIGetFlagIsBossDefeatedLastCheckpointScene 等)被 8 个文件通过 ServiceLocator.GetOrDefault<SaveManager>() 直接访问,绕过接口层。

根因BaseGames.Core.SaveBaseGames.Core 存在单向依赖约束Save 不引用 Core 导致 SaveManager 无法直接实现 ISaveService;历史上 SaveServiceAdapter 仅转发了最小集合。

受影响文件

  • Quest/ChallengeRoomManager.csQuickSave、IsFirstClear、QuickLoad
  • Quest/ChallengeRoomTrigger.csIsBossDefeated
  • EventChain/EventChainSO.csGetFlag、SetFlag
  • EventChain/EventChainManager.csGetCompletedChains、SetChainCompleted
  • Progression/HPContainerPickup.csIsWorldCollected、GetPlayerMaxHP
  • Progression/ProgressLock.csIsBossDefeated、IsDoorOpened
  • Core/DeathRespawnService.csLastCheckpointScene/SpawnId、DeleteSlotAsync、ActiveSlot
  • Support/AntiSoftlock/AntiSoftlockSystem.csLastCheckpointScene/SpawnId

修复方案:扩展 ISaveService 接口覆盖所有业务查询方法;扩展 SaveServiceAdapter 完整转发;所有 8 个文件改用 GetOrDefault<ISaveService>()

状态 已修复


B-2SaveManager / 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 IAudioServiceNullAudioService 兜底) 框架启动兜底
GameServiceRegistrar.cs IDeathRespawnService Persistent 服务
GameServiceRegistrar.cs ISceneService Persistent 服务
GameServiceRegistrar.cs IEventChannelRegistry Persistent 服务
GameServiceRegistrar.cs ISaveServicevia 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 拖慢场景打开