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]
14 KiB
14 KiB
值对象
**本文引用的文件** - [BindableProperty.cs](file://GFramework.Core/property/BindableProperty.cs) - [IBindableProperty.cs](file://GFramework.Core.Abstractions/property/IBindableProperty.cs) - [BindablePropertyUnRegister.cs](file://GFramework.Core/property/BindablePropertyUnRegister.cs) - [README.md(Property 包)](file://GFramework.Core/property/README.md) - [AbstractModel.cs](file://GFramework.Core/model/AbstractModel.cs) - [README.md(GFramework.Core)](file://GFramework.Core/README.md) - [advanced-patterns.md](file://docs/tutorials/advanced-patterns.md) - [AudioSettings.cs](file://GFramework.Game.Abstractions/setting/AudioSettings.cs) - [GraphicsSettings.cs](file://GFramework.Game.Abstractions/setting/GraphicsSettings.cs) - [ArchitectureProperties.cs](file://GFramework.Core.Abstractions/properties/ArchitectureProperties.cs) - [IsExternalInit.cs](file://GFramework.Game.Abstractions/internals/IsExternalInit.cs) - [BindablePropertyTests.cs](file://GFramework.Core.Tests/property/BindablePropertyTests.cs)目录
引言
本篇文档聚焦于 GFramework 中“值对象”的概念、设计原则与实现要点,结合框架内的可绑定属性(BindableProperty)与领域驱动设计(DDD)示例,系统阐述值对象的不可变性、相等性比较、构造函数验证、线程安全与组合嵌套等关键主题,并给出在游戏开发中的典型应用场景(位置坐标、颜色值、货币金额、技能等级等),以及与 GFramework 属性系统的集成方式。
项目结构
围绕值对象与属性系统的相关文件主要分布在以下模块:
- Core 层属性系统:可绑定属性类及其接口、注销器、使用说明与测试
- 抽象层接口:定义属性契约
- 示例与文档:DDD 值对象示例、设置类示例、架构配置示例
- 测试:可绑定属性的行为验证
graph TB
subgraph "Core 属性系统"
BP["BindableProperty<T>"]
IBind["IBindableProperty<T>"]
UnReg["BindablePropertyUnRegister<T>"]
PropReadme["Property 包使用说明"]
end
subgraph "抽象层接口"
AbsProp["IBindableProperty<T> 接口"]
ArchProps["ArchitectureProperties"]
end
subgraph "示例与文档"
DDD["advanced-patterns.md<br/>值对象示例"]
Audio["AudioSettings.cs"]
Graphics["GraphicsSettings.cs"]
ExtInit["IsExternalInit.cs"]
end
subgraph "测试"
BPT["BindablePropertyTests.cs"]
end
BP --> IBind
UnReg --> BP
PropReadme --> BP
AbsProp --> IBind
ArchProps --> PropReadme
DDD --> BP
Audio --> DDD
Graphics --> DDD
BPT --> BP
图表来源
- BindableProperty.cs
- IBindableProperty.cs
- BindablePropertyUnRegister.cs
- README.md(Property 包)
- ArchitectureProperties.cs
- advanced-patterns.md
- AudioSettings.cs
- GraphicsSettings.cs
- IsExternalInit.cs
- BindablePropertyTests.cs
章节来源
核心组件
- 可绑定属性(BindableProperty)
- 提供值变化监听与事件通知,支持自定义比较器、无事件设置、注册/注销等能力
- 通过静态比较器与实例比较器实现相等性判断,避免无效触发
- 可绑定属性接口(IBindableProperty)
- 定义可读写属性值与无事件设置方法
- 注销器(BindablePropertyUnRegister)
- 负责取消监听并清理引用,确保生命周期内资源释放
- 值对象示例(来自 DDD 文档)
- 使用 record 定义不可变值对象,构造函数中进行参数校验,提供派生构造与安全更新方法
- 设置类(示例)
- 音频设置、图形设置等作为普通类值对象,提供默认值与 Reset 行为
章节来源
- BindableProperty.cs
- IBindableProperty.cs
- BindablePropertyUnRegister.cs
- README.md(Property 包)
- advanced-patterns.md
- AudioSettings.cs
- GraphicsSettings.cs
架构总览
值对象与属性系统在 GFramework 中的协作关系如下:
- Model 层通过 BindableProperty 暴露可监听的状态
- Controller/View 通过注册监听实现数据绑定与 UI 更新
- 事件系统与属性系统共同构成响应式数据流
sequenceDiagram
participant Model as "Model可绑定属性"
participant Controller as "ControllerUI/逻辑"
participant Bus as "事件系统"
participant View as "ViewUI"
Controller->>Model : 注册监听Register/ RegisterWithInitValue
Model-->>Controller : 初始值回传RegisterWithInitValue
Controller->>Model : 设置值Value = ...
Model->>Model : 比较器判断相等性
alt 值变化
Model-->>Controller : 触发回调
Controller->>View : 更新 UI
Controller->>Bus : 发送事件可选
else 值未变化
Model-->>Controller : 不触发回调
end
图表来源
详细组件分析
组件一:可绑定属性(BindableProperty)
- 不可变性与构造函数验证
- 通过构造函数设定默认值;在设置值前进行相等性判断,避免无效触发
- 支持静态比较器与 WithComparer 实例方法,满足不同场景下的相等性语义
- 相等性比较
- 默认使用 EqualityComparer.Default 进行比较;可通过 Comparer 静态字段或 WithComparer 自定义
- 针对浮点数等场景,建议使用 WithComparer 提供容差比较,减少抖动触发
- 线程安全
- 属性值的读写与事件触发在单线程上下文中进行;若需跨线程访问,应在调用方保证线程安全
- 事件与注销
- Register/RegisterWithInitValue 提供监听注册;UnRegister 解除监听;BindablePropertyUnRegister 负责清理
- 与 Model 的集成
- Model 层定义 BindableProperty,Controller 层注册监听实现 UI 绑定;测试覆盖了基本行为与自定义比较器
classDiagram
class BindableProperty_T_ {
+T Value
+static Comparer(a,b) bool
+Register(handler) IUnRegister
+RegisterWithInitValue(action) IUnRegister
+UnRegister(handler) void
+SetValueWithoutEvent(newValue) void
+WithComparer(comparer) BindableProperty_T_
#SetValue(newValue) void
#GetValue() T
+ToString() string
}
class IBindableProperty_T_ {
+T Value
+SetValueWithoutEvent(newValue) void
}
class BindablePropertyUnRegister_T_ {
+BindableProperty<T> BindableProperty
+Action<T> OnValueChanged
+UnRegister() void
}
BindableProperty_T_ ..|> IBindableProperty_T_
BindablePropertyUnRegister_T_ --> BindableProperty_T_ : "注销监听"
图表来源
章节来源
- BindableProperty.cs
- IBindableProperty.cs
- BindablePropertyUnRegister.cs
- README.md(Property 包)
- BindablePropertyTests.cs
组件二:值对象(DDD 示例)
- 不可变性
- 使用 record 定义值对象,字段为只读,构造后不可变
- 构造函数验证
- 在构造函数中进行参数校验(如范围、非空、格式),不符合条件抛出异常
- 安全更新
- 通过返回新实例的方式实现“更新”,保持原值不变
- 组合与嵌套
- 值对象可作为其他值对象的组成部分(如 Health 同时包含当前值与最大值)
flowchart TD
Start(["创建值对象"]) --> Validate["构造函数参数校验"]
Validate --> Valid{"校验通过?"}
Valid --> |否| Throw["抛出异常"]
Valid --> |是| Build["构建不可变实例"]
Build --> Use["在领域逻辑中使用"]
Use --> Update["返回新实例组合/嵌套"]
Update --> Use
图表来源
章节来源
组件三:设置类(值对象示例)
- 音频设置(AudioSettings)
- 包含主音量、背景音乐音量、音效音量等属性,提供 Reset 方法恢复默认值
- 图形设置(GraphicsSettings)
- 包含全屏、分辨率宽高属性,提供 Reset 方法恢复默认值
- 适用场景
- 作为持久化配置的值对象载体,便于序列化与版本迁移
章节来源
组件四:架构属性(ArchitectureProperties)
- AllowLateRegistration:允许在初始化完成后进行组件注册
- StrictPhaseValidation:启用严格的阶段验证机制
- 与值对象的关系
- 架构配置可影响值对象所在组件的生命周期与注册时机,间接影响值对象的可用性
章节来源
依赖关系分析
- BindableProperty 依赖 IBindableProperty 接口与事件系统(通过注册回调实现通知)
- Model 通过 AbstractModel 提供生命周期钩子,便于在 OnInit 中初始化可绑定属性
- 值对象示例与设置类作为数据载体,与属性系统协同工作
- 测试用例覆盖了基本行为、比较器与注销流程
graph LR
IBind["IBindableProperty<T>"] --> BP["BindableProperty<T>"]
BP --> UnReg["BindablePropertyUnRegister<T>"]
Model["AbstractModel"] --> BP
DDD["值对象示例"] --> BP
Settings["设置类示例"] --> BP
Tests["BindablePropertyTests"] --> BP
图表来源
- IBindableProperty.cs
- BindableProperty.cs
- BindablePropertyUnRegister.cs
- AbstractModel.cs
- advanced-patterns.md
- AudioSettings.cs
- GraphicsSettings.cs
- BindablePropertyTests.cs
章节来源
性能考量
- 避免频繁触发
- 使用 SetValueWithoutEvent 进行批量更新,最后统一触发一次事件,降低 UI 刷新与事件风暴
- 自定义比较器
- 对浮点数等需要精度控制的属性,使用 WithComparer 提供容差比较,减少因微小差异导致的无效触发
- 监听管理
- 使用 RegisterWithInitValue 首次即获取当前值,避免重复渲染;及时注销监听,防止内存泄漏与逻辑错误
章节来源
故障排查指南
- 设置相同值仍触发事件
- 检查 Comparer 是否被全局或实例级自定义覆盖,确认比较逻辑是否符合预期
- 注销后仍收到回调
- 确认是否正确调用 UnRegister 或使用 BindablePropertyUnRegister 的 UnRegister 方法
- UI 不更新
- 确认使用 RegisterWithInitValue 获取初始值;检查监听是否在正确的生命周期内注册
- 测试失败
- 参考单元测试用例,验证默认行为、比较器、注销与 ToString 等关键路径
章节来源
结论
值对象在 GFramework 中通过 record 的不可变性与构造函数验证实现强健的数据建模;与可绑定属性系统结合,既保证了数据一致性,又实现了响应式的数据绑定与事件通知。通过自定义比较器、批量更新与完善的监听管理,能够在游戏开发中高效地处理位置坐标、颜色值、货币金额、技能等级等常见场景,并与架构配置、事件系统形成一致的开发范式。
附录
- 术语
- 值对象:仅由数据组成、不可变、按值比较的领域对象
- 可绑定属性:支持监听与事件通知的属性封装
- 参考路径