GeWuYou a79f02c987 docs(api): 添加 Core API 参考文档与事件系统接口文档
- 新增 Core API 参考文档,涵盖架构与模块、数据模型与系统、命令与查询等核心组件
- 添加事件系统接口详细文档,包括 IEvent、IEventBus、IUnRegister 等接口说明
- 提供完整的 API 使用示例路径、最佳实践与性能建议
- 包含架构图、依赖关系图与故障排查指南
- 添加测试用例参考与扩展方法说明
- [skip ci]
2026-01-21 23:45:10 +08:00

18 KiB
Raw Blame History

设置持久化

**本文引用的文件** - [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs) - [ISettingsPersistence.cs](file://GFramework.Game.Abstractions/setting/ISettingsPersistence.cs) - [ISettingsChangedEvent.cs](file://GFramework.Game.Abstractions/setting/ISettingsChangedEvent.cs) - [SettingsChangedEvent.cs](file://GFramework.Game/setting/events/SettingsChangedEvent.cs) - [SettingsModel.cs](file://GFramework.Game/setting/SettingsModel.cs) - [SettingsSystem.cs](file://GFramework.Game/setting/SettingsSystem.cs) - [FileStorage.cs](file://GFramework.Game/storage/FileStorage.cs) - [IFileStorage.cs](file://GFramework.Game.Abstractions/storage/IFileStorage.cs) - [ISerializer.cs](file://GFramework.Game.Abstractions/serializer/ISerializer.cs) - [JsonSerializer.cs](file://GFramework.Game/serializer/JsonSerializer.cs) - [ISettingsData.cs](file://GFramework.Game.Abstractions/setting/ISettingsData.cs) - [ISettingsSection.cs](file://GFramework.Game.Abstractions/setting/ISettingsSection.cs) - [SettingsData.cs](file://GFramework.Game.Abstractions/setting/SettingsData.cs) - [AudioSettings.cs](file://GFramework.Game.Abstractions/setting/AudioSettings.cs)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排除指南
  9. 结论
  10. 附录

简介

本文件围绕 GFramework 的设置持久化子系统,系统性梳理 SettingsPersistence 类的持久化策略、ISettingsPersistence 接口设计原则、设置变更事件模型与通知机制,并对数据校验、版本兼容性与错误恢复策略进行说明。同时给出配置选项、性能优化建议与不同存储场景的最佳实践与迁移策略。

项目结构

设置持久化相关代码主要分布在以下模块:

  • 抽象层定义接口与契约ISettingsPersistence、ISettingsData、ISettingsSection、ISerializer、IFileStorage 等)
  • 具体实现SettingsPersistence 负责加载/保存/删除/批量操作FileStorage 提供基于文件的存储JsonSerializer 提供 JSON 序列化能力
  • 事件与系统SettingsChangedEvent 变更事件模型SettingsSystem 负责应用设置SettingsModel 管理设置节与可应用设置
graph TB
subgraph "抽象层"
A["ISettingsPersistence.cs"]
B["ISettingsData.cs"]
C["ISettingsSection.cs"]
D["ISerializer.cs"]
E["IFileStorage.cs"]
end
subgraph "具体实现"
F["SettingsPersistence.cs"]
G["FileStorage.cs"]
H["JsonSerializer.cs"]
end
subgraph "事件与系统"
I["ISettingsChangedEvent.cs"]
J["SettingsChangedEvent.cs"]
K["SettingsSystem.cs"]
L["SettingsModel.cs"]
end
A --> F
B --> F
C --> F
D --> H
E --> G
F --> G
F --> I
J --> I
K --> L

图表来源

章节来源

核心组件

  • SettingsPersistence实现 ISettingsPersistence封装对 IStorage 的读写与事件派发,提供单个与批量的加载/保存/删除能力,并生成 SettingsLoaded/SettingsSaved/SettingsDeleted/SettingsBatchSaved 等事件
  • ISettingsPersistence定义异步 LoadAsync/SaveAsync/ExistsAsync/DeleteAsync/SaveAllAsync/LoadAllAsync 等契约
  • FileStorage基于文件系统的 IFileStorage 实现提供线程安全的读写、键名到路径的映射、UTF-8 文本读写与 JSON 序列化
  • JsonSerializer基于 Newtonsoft.Json 的 ISerializer 实现,负责对象与 JSON 字符串之间的转换
  • SettingsSystem负责应用设置TryApply并在应用前后发送 SettingsApplying/SettingsApplied 事件
  • SettingsModel管理 ISettingsData 与 IApplyAbleSettings 的注册与检索,聚合所有设置节
  • ISettingsChangedEvent/SettingsChangedEvent设置变更事件模型携带设置类型、实例与变更时间

章节来源

架构总览

设置持久化采用“接口抽象 + 具体实现 + 事件驱动 + 应用系统”的分层设计。持久化层通过 IStorage 抽象屏蔽底层介质差异;序列化层通过 ISerializer 解耦序列化算法;事件层提供统一的变更通知;系统层负责应用与异常传播。

classDiagram
class ISettingsPersistence {
+LoadAsync<T>()
+SaveAsync<T>()
+ExistsAsync<T>()
+DeleteAsync<T>()
+SaveAllAsync(allData)
+LoadAllAsync(knownTypes)
}
class SettingsPersistence {
-IStorage _storage
+LoadAsync<T>()
+SaveAsync<T>()
+ExistsAsync<T>()
+DeleteAsync<T>()
+SaveAllAsync(allData)
+LoadAllAsync(knownTypes)
}
class IStorage
class IFileStorage
class FileStorage {
-string _rootPath
-ISerializer _serializer
+ReadAsync<T>(key)
+WriteAsync<T>(key, value)
+ExistsAsync(key)
+Delete(key)
}
class ISerializer
class JsonSerializer {
+Serialize<T>(value)
+Deserialize<T>(data)
}
class ISettingsData
class ISettingsSection
class SettingsSystem {
+ApplyAll()
+Apply<T>()
+Apply(types)
}
class SettingsModel {
+GetData<T>()
+RegisterApplicator<T>(applicator)
+GetApplicator<T>()
+TryGet(type, out section)
+All()
}
ISettingsPersistence <|.. SettingsPersistence
IStorage <|.. IFileStorage
IFileStorage <|.. FileStorage
ISerializer <|.. JsonSerializer
ISettingsData <|-- ISettingsSection
SettingsPersistence --> IStorage : "依赖"
SettingsPersistence --> ISerializer : "依赖"
SettingsSystem --> SettingsModel : "依赖"

图表来源

详细组件分析

SettingsPersistence 持久化策略

  • 数据序列化
    • 通过 ISerializer 将对象序列化为字符串写入文件,读取时再反序列化回对象
    • FileStorage 在读写时使用 UTF-8 编码,确保跨平台一致性
  • 存储介质选择
    • 默认使用 FileStorageIFileStorage键名映射到文件路径支持目录分层与扩展名
    • 键名到路径映射包含防路径穿越与非法字符清理
  • 加载机制
    • LoadAsync():若键存在则读取并派发 SettingsLoaded 事件;否则创建新实例并派发事件
    • LoadAllAsync(knownTypes):按类型集合批量读取,使用反射调用 IStorage.ReadAsync 并派发 SettingsAllLoaded
  • 保存与删除
    • SaveAsync():写入并派发 SettingsSaved
    • DeleteAsync():删除并派发 SettingsDeleted
    • SaveAllAsync(IEnumerable):遍历写入并派发 SettingsBatchSaved
  • 键命名策略
    • GetKey() 返回 "Settings_{TypeName}",避免冲突并便于调试
sequenceDiagram
participant Caller as "调用方"
participant SP as "SettingsPersistence"
participant Store as "IStorage(FileStorage)"
participant Ser as "ISerializer(JsonSerializer)"
Caller->>SP : "LoadAsync<T>()"
SP->>Store : "ExistsAsync(key)"
alt "存在"
SP->>Store : "ReadAsync<T>(key)"
Store->>Ser : "Deserialize<T>(content)"
Ser-->>Store : "T 实例"
Store-->>SP : "T 实例"
SP-->>Caller : "返回实例"
else "不存在"
SP-->>Caller : "new T()"
end

图表来源

章节来源

ISettingsPersistence 接口设计原则

  • 方法职责清晰Load/Save/Exists/Delete/SaveAll/LoadAll 分别覆盖单体与批量场景
  • 泛型约束明确T : class, ISettingsData, new() 确保可自动创建T : class, ISettingsData 确保可序列化
  • 异步优先:所有操作均为 Task/Task适配高并发与 UI 线程不阻塞
  • 扩展性:新增存储介质只需实现 IStorage无需修改上层调用

章节来源

设置变更事件系统

  • ISettingsChangedEvent统一事件模型包含 SettingsType、Settings、ChangedAt
  • SettingsChangedEvent泛型事件承载具体设置实例便于订阅者按类型处理
  • SettingsSystem在应用前派发 SettingsApplying应用成功/失败分别派发 SettingsApplied含结果与异常
sequenceDiagram
participant Model as "SettingsModel"
participant Sys as "SettingsSystem"
participant Bus as "事件总线"
participant Sub as "订阅者"
Model->>Sys : "Apply<T>()"
Sys->>Bus : "Send(SettingsApplying<T>)"
Sys->>Sys : "TryApply(section)"
alt "成功"
Sys->>Bus : "Send(SettingsApplied<T>(true))"
else "失败"
Sys->>Bus : "Send(SettingsApplied<T>(false, ex))"
end
Bus-->>Sub : "事件回调"

图表来源

章节来源

数据校验、版本兼容性与错误恢复

  • 数据校验
    • FileStorage 对键名进行清理与路径穿越防护,防止非法字符与目录逃逸
    • 读取失败抛出 FileNotFoundException调用方可据此决定是否创建默认实例
  • 版本兼容性
    • SettingsData.Reset() 使用反射将属性重置为默认值,便于未来字段增删的向后兼容
    • 建议在业务设置类中显式实现 Reset() 以精确控制默认值
  • 错误恢复
    • LoadAsync() 在键不存在时返回新实例,避免崩溃
    • SettingsSystem.TryApply 捕获异常并派发失败事件,随后重新抛出,便于上层处理

章节来源

持久化配置选项与最佳实践

  • 存储介质选择
    • FileStorage适合本地文件系统键名映射到文件路径注意磁盘空间与权限
    • 若需云同步或内存缓存,可实现 IStorage 的其他实现(如 IScopedStorage并与 SettingsPersistence 解耦
  • 序列化策略
    • 默认 JSON确保设置类具备无参构造函数与可序列化属性
    • 大对象建议压缩或分块存储,避免单文件过大
  • 键命名与组织
    • 使用 GetKey 规则统一前缀,必要时引入命名空间/分组层级
  • 事件与应用
    • 仅 IApplyAbleSettings 才会被 SettingsSystem 应用,避免非数据类被误应用
    • 订阅 SettingsApplying/SettingsApplied 以实现副作用(如刷新 UI、写入日志

章节来源

依赖关系分析

  • SettingsPersistence 依赖 IStorage 与 ISerializer解耦存储介质与序列化算法
  • SettingsSystem 依赖 SettingsModel通过 ISettingsSection/IApplyAbleSettings 控制应用流程
  • SettingsModel 聚合 ISettingsData 与 IApplyAbleSettings提供统一访问入口
graph LR
SP["SettingsPersistence"] --> ST["IStorage/FileStorage"]
SP --> SR["ISerializer/JsonSerializer"]
SS["SettingsSystem"] --> SM["SettingsModel"]
SM --> SD["ISettingsData"]
SM --> SA["IApplyAbleSettings"]

图表来源

章节来源

性能考虑

  • 线程安全与锁粒度
    • FileStorage 为每个路径维护独立锁对象,降低争用;读多写少场景建议合并写入批次
  • 异步 I/O
    • ReadAsync/WriteAsync 已异步化,但仍需持有锁;建议批量写入时减少锁竞争
  • 序列化成本
    • 大对象或频繁写入时,考虑二进制序列化或增量更新策略
  • 事件风暴
    • SaveAllAsync 会触发多次事件;订阅者应避免在事件中执行耗时操作

章节来源

故障排除指南

  • 读取失败FileNotFoundException
    • 现象LoadAsync/ReadAsync 抛出文件未找到异常
    • 处理:捕获异常后创建新实例或回退到默认值
  • 路径异常ArgumentException
    • 现象:键名包含非法字符或 ".."
    • 处理:检查键名生成逻辑,确保符合 ToPath 约束
  • 应用失败(异常事件)
    • 现象SettingsApplied(false, ex) 被派发
    • 处理:记录异常详情,回滚或提示用户
  • 迁移与兼容
    • 新增字段:使用 SettingsData.Reset 或在具体设置类中实现 Reset保持默认值一致
    • 重命名字段:在反序列化兼容层处理字段映射(如 JSON 属性名映射)

章节来源

结论

SettingsPersistence 通过清晰的接口与事件模型,结合 FileStorage 与 JsonSerializer提供了稳定、可扩展的设置持久化方案。其异步设计与线程安全策略满足多场景需求配合 SettingsSystem 的应用流程与 SettingsModel 的聚合管理,形成完整的设置生命周期闭环。建议在生产环境中关注键命名规范、序列化兼容与事件处理性能,并根据部署环境选择合适的存储介质。

附录

  • 示例设置类(音频设置)
    • AudioSettings演示如何实现 ISettingsData 并提供 Reset() 默认值
  • 关键流程图(批量加载)
flowchart TD
Start(["开始"]) --> Iterate["遍历已知类型集合"]
Iterate --> GenKey["生成键名"]
GenKey --> Exists{"键存在?"}
Exists --> |否| Skip["跳过该类型"]
Exists --> |是| Read["调用 IStorage.ReadAsync<T>"]
Read --> Add["加入结果字典与列表"]
Skip --> Next["下一个类型"]
Add --> Next
Next --> Done{"全部处理完?"}
Done --> |否| Iterate
Done --> |是| Emit["派发 SettingsAllLoaded 事件"]
Emit --> End(["结束"])

图表来源