mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-26 06:16:43 +08:00
- 新增 Core API 参考文档,涵盖架构与模块、数据模型与系统、命令与查询等核心组件 - 添加事件系统接口详细文档,包括 IEvent、IEventBus、IUnRegister 等接口说明 - 提供完整的 API 使用示例路径、最佳实践与性能建议 - 包含架构图、依赖关系图与故障排查指南 - 添加测试用例参考与扩展方法说明 - [skip ci]
20 KiB
20 KiB
设置模型
**本文引用的文件** - [SettingsModel.cs](file://GFramework.Game/setting/SettingsModel.cs) - [ISettingsModel.cs](file://GFramework.Game.Abstractions/setting/ISettingsModel.cs) - [ISettingsSection.cs](file://GFramework.Game.Abstractions/setting/ISettingsSection.cs) - [ISettingsData.cs](file://GFramework.Game.Abstractions/setting/ISettingsData.cs) - [SettingsSystem.cs](file://GFramework.Game/setting/SettingsSystem.cs) - [ISettingsPersistence.cs](file://GFramework.Game.Abstractions/setting/ISettingsPersistence.cs) - [SettingsPersistence.cs](file://GFramework.Game/setting/SettingsPersistence.cs) - [IApplyAbleSettings.cs](file://GFramework.Game.Abstractions/setting/IApplyAbleSettings.cs) - [SettingsData.cs](file://GFramework.Game.Abstractions/setting/SettingsData.cs) - [AudioSettings.cs](file://GFramework.Game.Abstractions/setting/AudioSettings.cs) - [GraphicsSettings.cs](file://GFramework.Game.Abstractions/setting/GraphicsSettings.cs) - [GodotAudioSettings.cs](file://GFramework.Godot/setting/GodotAudioSettings.cs) - [GodotGraphicsSettings.cs](file://GFramework.Godot/setting/GodotGraphicsSettings.cs) - [SettingsChangedEvent.cs](file://GFramework.Game/setting/events/SettingsChangedEvent.cs) - [SettingsAllLoadedEvent.cs](file://GFramework.Game/setting/events/SettingsAllLoadedEvent.cs)目录
简介
本文件面向 GFramework 的“设置模型”子系统,系统性阐述 SettingsModel 类的数据存储机制、ISettingsModel 接口的设计模式、ISettingsSection 的结构化定义、ISettingsData 的数据契约与序列化要求,并给出 API 参考、数据结构示例与典型应用场景。同时,文档覆盖设置数据的一致性保证与并发访问控制建议。
项目结构
设置模型相关代码分布在以下模块:
- 抽象层(Abstractions):定义接口契约与通用抽象基类
- 游戏实现层(Game):提供具体实现(模型、系统、持久化)
- 平台适配层(Godot):针对 Godot 引擎的具体应用器实现
graph TB
subgraph "抽象层"
A["ISettingsModel.cs"]
B["ISettingsSection.cs"]
C["ISettingsData.cs"]
D["IApplyAbleSettings.cs"]
E["ISettingsPersistence.cs"]
F["SettingsData.cs"]
end
subgraph "游戏实现层"
G["SettingsModel.cs"]
H["SettingsSystem.cs"]
I["SettingsPersistence.cs"]
end
subgraph "平台适配层"
J["GodotAudioSettings.cs"]
K["GodotGraphicsSettings.cs"]
end
A --> G
B --> C
B --> D
C --> F
E --> I
G --> H
H --> D
I --> E
D --> J
D --> K
图表来源
- ISettingsModel.cs
- ISettingsSection.cs
- ISettingsData.cs
- IApplyAbleSettings.cs
- ISettingsPersistence.cs
- SettingsData.cs
- SettingsModel.cs
- SettingsSystem.cs
- SettingsPersistence.cs
- GodotAudioSettings.cs
- GodotGraphicsSettings.cs
章节来源
核心组件
- SettingsModel:集中管理“数据设置”和“可应用设置”,提供注册、检索与聚合查询能力
- SettingsSystem:负责应用设置(调用 IApplyAbleSettings.Apply),并发布生命周期事件
- SettingsPersistence:负责设置数据的异步加载、保存、存在性检查与批量操作
- ISettingsData/SettingsData:纯数据设置的契约与默认重置行为
- ISettingsSection/IApplyAbleSettings:设置节的结构化定义与可应用设置的执行契约
- 平台应用器(Godot*Settings):将设置应用到具体平台(如 Godot 音频/图形)
章节来源
- SettingsModel.cs
- SettingsSystem.cs
- SettingsPersistence.cs
- ISettingsData.cs
- SettingsData.cs
- IApplyAbleSettings.cs
- ISettingsSection.cs
架构总览
设置模型采用“模型-系统-持久化”的分层设计,通过接口隔离关注点,确保跨平台可扩展性。
sequenceDiagram
participant Client as "调用方"
participant Model as "SettingsModel"
participant Sys as "SettingsSystem"
participant Persist as "SettingsPersistence"
participant Storage as "IStorage"
Client->>Persist : "LoadAsync<T>()"
Persist->>Storage : "ExistsAsync(key)"
alt 存在
Persist->>Storage : "ReadAsync<T>(key)"
Storage-->>Persist : "T 实例"
Persist-->>Client : "返回已加载设置"
else 不存在
Persist-->>Client : "返回新实例"
end
Client->>Sys : "ApplyAll()"
Sys->>Model : "All()"
Model-->>Sys : "IEnumerable<ISettingsSection>"
loop 遍历每个设置节
Sys->>Sys : "TryApply(section)"
alt section 实现 IApplyAbleSettings
Sys-->>Sys : "Send(SettingsApplyingEvent)"
Sys->>section : "Apply()"
Sys-->>Sys : "Send(SettingsAppliedEvent)"
else
Sys-->>Sys : "忽略"
end
end
图表来源
详细组件分析
SettingsModel:设置模型与数据存储机制
- 数据存储机制
- 数据设置(ISettingsData):以类型为键缓存,首次访问自动创建并放入字典;后续访问直接返回同一实例
- 可应用设置(IApplyAbleSettings):显式注册,按类型检索;用于将设置应用到平台或系统
- 注册、检索与聚合
- GetData():自动创建并缓存
- RegisterApplicator():注册可应用设置,支持链式调用
- GetApplicator():按类型获取可应用设置(可空)
- TryGet(Type, out ISettingsSection):优先从数据设置查找,再从可应用设置查找
- All():合并两类设置节的值,统一暴露给系统进行应用
- 设计要点
- 通过两个独立字典隔离“数据持有者”和“应用执行者”,职责清晰
- 自动创建策略降低调用方心智负担,但需注意生命周期与重置策略
classDiagram
class SettingsModel {
-Dictionary~Type,ISettingsData~ _dataSettings
-Dictionary~Type,IApplyAbleSettings~ _applicators
+GetData~T~() T
+RegisterApplicator~T~(T) ISettingsModel
+GetApplicator~T~() T?
+TryGet(Type, out ISettingsSection) bool
+All() IEnumerable~ISettingsSection~
}
class ISettingsData {
<<interface>>
+Reset() void
}
class IApplyAbleSettings {
<<interface>>
+Apply() Task
}
class ISettingsSection {
<<interface>>
}
SettingsModel ..|> ISettingsModel
ISettingsData --|> ISettingsSection
IApplyAbleSettings --|> ISettingsSection
图表来源
章节来源
ISettingsModel 接口:设计模式与使用场景
- 方法语义
- GetData():自动创建并缓存,适合“读多写少”的配置项
- TryGet(Type, out ISettingsSection):安全检索,避免异常传播
- GetApplicator():获取应用器,常用于平台适配层
- All():统一聚合,便于系统一次性应用
- RegisterApplicator():显式注册,确保应用器可用
- 使用场景
- 初始化阶段:通过 GetData() 获取并可能触发 LoadAsync()
- 应用阶段:通过 All()/TryGet() 遍历并调用 Apply()
- 维护阶段:通过 Reset() 或重置流程恢复默认值
章节来源
ISettingsSection 与 ISettingsData:结构化定义与数据契约
- ISettingsSection:设置节的最小契约,用于区分“数据设置”和“可应用设置”
- ISettingsData:继承 ISettingsSection,强调“纯数据”特性,并提供 Reset() 重置能力
- SettingsData 抽象基类:提供基于反射的默认 Reset() 实现,按属性类型设置默认值
classDiagram
class ISettingsSection {
<<interface>>
}
class ISettingsData {
<<interface>>
+Reset() void
}
class SettingsData {
+Reset() void
-GetDefaultValue(Type) object?
}
ISettingsData --|> ISettingsSection
SettingsData ..|> ISettingsData
图表来源
章节来源
IApplyAbleSettings 与 SettingsSystem:应用与事件
- IApplyAbleSettings:定义 Apply() 异步方法,用于将设置应用到平台或系统
- SettingsSystem:遍历模型中的所有设置节,识别可应用设置并调用 Apply(),期间发送“正在应用/已应用”事件
- 事件模型:通过事件总线广播设置变更与应用结果,便于 UI 或日志系统订阅
sequenceDiagram
participant Sys as "SettingsSystem"
participant Model as "SettingsModel"
participant Sec as "ISettingsSection"
participant App as "IApplyAbleSettings"
Sys->>Model : "All()"
Model-->>Sys : "IEnumerable<ISettingsSection>"
loop 遍历
Sys->>Sec : "TryApply(section)"
alt section 实现 IApplyAbleSettings
Sys-->>Sys : "Send(SettingsApplyingEvent)"
Sys->>App : "Apply()"
Sys-->>Sys : "Send(SettingsAppliedEvent)"
else
Sys-->>Sys : "忽略"
end
end
图表来源
章节来源
SettingsPersistence 与 ISettingsPersistence:序列化与一致性
- 职责边界
- LoadAsync():若存储存在则反序列化,否则返回新实例;均发送“已加载”事件
- SaveAsync():序列化并写入存储,发送“已保存”事件
- ExistsAsync():检查键是否存在
- DeleteAsync():删除键并发送“已删除”事件
- SaveAllAsync/LoadAllAsync:批量写入与批量加载,支持事件聚合
- 键命名约定:Settings_{TypeName}
- 一致性保证
- 读取失败时返回新实例,避免崩溃;写入成功后才认为一致
- 批量操作通过事件聚合(如 SettingsAllLoadedEvent)通知上层
- 并发访问控制建议
- 对同一类型设置的并发读写应加锁或使用原子更新策略
- 批量保存/加载建议串行化,避免竞态条件
- 事件发布与存储写入顺序:先写入存储,再发布事件,确保订阅者看到最新状态
flowchart TD
Start(["开始"]) --> Check["ExistsAsync(key)"]
Check --> |存在| Read["ReadAsync<T>(key)"]
Check --> |不存在| New["new T()"]
Read --> Loaded["发送 SettingsLoadedEvent"]
New --> Loaded
Loaded --> End(["结束"])
图表来源
章节来源
平台应用器示例:GodotAudioSettings 与 GodotGraphicsSettings
- GodotAudioSettings:将线性音量转换为分贝并设置到对应音频总线
- GodotGraphicsSettings:根据图形设置调整窗口模式、尺寸与居中
- 共同特点:实现 IApplyAbleSettings,接收对应数据设置作为输入,在 Apply() 中执行平台特定逻辑
classDiagram
class AudioSettings {
+float MasterVolume
+float BgmVolume
+float SfxVolume
+Reset() void
}
class GraphicsSettings {
+bool Fullscreen
+int ResolutionWidth
+int ResolutionHeight
+Reset() void
}
class GodotAudioSettings {
+Apply() Task
-SetBus(string,float) void
}
class GodotGraphicsSettings {
+Apply() Task
}
AudioSettings ..|> ISettingsData
GraphicsSettings ..|> ISettingsData
GodotAudioSettings ..|> IApplyAbleSettings
GodotGraphicsSettings ..|> IApplyAbleSettings
图表来源
章节来源
依赖关系分析
- 松耦合:通过接口隔离(ISettingsModel、ISettingsData、IApplyAbleSettings、ISettingsPersistence)实现跨模块协作
- 可替换性:SettingsPersistence 可替换为其他存储实现(文件、内存、网络),不影响上层逻辑
- 循环依赖:未见循环依赖;模型与系统通过接口交互,系统与持久化通过接口交互
graph LR
Model["SettingsModel"] --> Abstractions["ISettingsModel/ISettingsData/IApplyAbleSettings"]
System["SettingsSystem"] --> Model
Persistence["SettingsPersistence"] --> Storage["IStorage"]
Persistence --> Abstractions
System --> Abstractions
Platform["Godot*Settings"] --> Abstractions
图表来源
章节来源
性能考量
- 访问模式
- GetData() 为 O(1) 查找+首次创建成本,建议在初始化阶段预热常用设置
- All() 返回合并后的集合,遍历时注意避免重复计算
- 序列化
- 大型设置对象建议分块加载或延迟初始化
- 批量保存/加载时尽量减少事件风暴,必要时合并事件
- 并发
- 对同一类型设置的并发读写建议加锁或使用不可变快照
- Apply() 为异步,避免阻塞主线程;UI 更新应在主线程回调中进行
故障排查指南
- 症状:设置未生效
- 检查是否注册了对应的 IApplyAbleSettings 实现
- 确认 SettingsSystem.ApplyAll() 已被调用
- 关注 SettingsAppliedEvent 是否携带异常信息
- 症状:设置丢失或重置
- 检查 IStorage 是否正常工作
- 确认 SettingsPersistence 的键命名规则(Settings_{TypeName})
- 若存在竞态,考虑引入互斥锁或原子更新
- 症状:事件未触发
- 确认事件总线已正确初始化
- 检查 SendEvent 调用路径与异常捕获
章节来源
结论
设置模型通过清晰的接口分层与职责分离,提供了可扩展、可测试且易于维护的设置管理方案。数据设置与可应用设置的双通道设计,既满足了“读多写少”的数据访问需求,又允许平台层以统一契约执行应用逻辑。配合事件总线与持久化抽象,系统可在不同平台与存储介质间灵活切换。
附录:API 参考与数据结构示例
API 参考(摘自接口定义)
- ISettingsModel
- GetData():获取或创建数据设置
- TryGet(Type, out ISettingsSection):安全检索设置节
- GetApplicator():获取可应用设置
- All():获取全部设置节
- RegisterApplicator(T):注册可应用设置
- ISettingsData
- Reset():重置为默认值
- IApplyAbleSettings
- Apply():应用设置到平台
- ISettingsPersistence
- LoadAsync()、SaveAsync()、ExistsAsync()、DeleteAsync()
- SaveAllAsync(IEnumerable)、LoadAllAsync(IEnumerable)
章节来源
数据结构示例(类型与字段)
- AudioSettings:主音量、背景音乐音量、音效音量
- GraphicsSettings:全屏开关、分辨率宽高
- GodotAudioSettings/GodotGraphicsSettings:平台应用器,接收对应数据设置并在 Apply() 中执行平台逻辑
章节来源
实际应用场景
- 游戏启动时:通过 SettingsPersistence.LoadAllAsync 加载已知类型设置,随后 SettingsSystem.ApplyAll 应用到平台
- 设置面板修改后:调用 SettingsPersistence.SaveAsync 保存,同时触发事件通知 UI 刷新
- 重置功能:调用 ISettingsData.Reset() 或平台应用器的回滚逻辑