mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 21:34:28 +08:00
- 新增 Core API 参考文档,涵盖架构与模块、数据模型与系统、命令与查询等核心组件 - 添加事件系统接口详细文档,包括 IEvent、IEventBus、IUnRegister 等接口说明 - 提供完整的 API 使用示例路径、最佳实践与性能建议 - 包含架构图、依赖关系图与故障排查指南 - 添加测试用例参考与扩展方法说明 - [skip ci]
20 KiB
20 KiB
查询基类体系
**本文引用的文件** - [AbstractQuery.cs](file://GFramework.Core/query/AbstractQuery.cs) - [AbstractAsyncQuery.cs](file://GFramework.Core/query/AbstractAsyncQuery.cs) - [EmptyQueryInput.cs](file://GFramework.Core/query/EmptyQueryInput.cs) - [QueryBus.cs](file://GFramework.Core/query/QueryBus.cs) - [AsyncQueryBus.cs](file://GFramework.Core/query/AsyncQueryBus.cs) - [IQuery.cs](file://GFramework.Core.Abstractions/query/IQuery.cs) - [IAsyncQuery.cs](file://GFramework.Core.Abstractions/query/IAsyncQuery.cs) - [IQueryBus.cs](file://GFramework.Core.Abstractions/query/IQueryBus.cs) - [IAsyncQueryBus.cs](file://GFramework.Core.Abstractions/query/IAsyncQueryBus.cs) - [IQueryInput.cs](file://GFramework.Core.Abstractions/query/IQueryInput.cs) - [ContextAwareBase.cs](file://GFramework.Core/rule/ContextAwareBase.cs) - [IContextAware.cs](file://GFramework.Core.Abstractions/rule/IContextAware.cs) - [QueryBusTests.cs](file://GFramework.Core.Tests/query/QueryBusTests.cs) - [AsyncQueryBusTests.cs](file://GFramework.Core.Tests/query/AsyncQueryBusTests.cs) - [AbstractAsyncQueryTests.cs](file://GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs)目录
引言
本文件系统化梳理查询基类体系,围绕以下目标展开:深入解释同步与异步查询基类的设计理念与实现细节;阐明查询执行接口的契约与实现要求;说明查询输入模型的设计模式(含 EmptyQueryInput 的使用场景与自定义输入类型的实现方法);解释查询生命周期(创建、验证、执行、结果处理);给出继承与扩展示例;介绍参数验证机制与结果映射策略;说明与架构其他组件的集成方式,并总结最佳实践、性能优化与缓存策略。
项目结构
查询体系位于 GFramework.Core 与 GFramework.Core.Abstractions 两个工程中,分别提供具体实现与抽象契约。核心文件分布如下:
- 抽象层(契约):IQuery、IAsyncQuery、IQueryBus、IAsyncQueryBus、IQueryInput、IContextAware
- 具体实现:AbstractQuery、AbstractAsyncQuery、EmptyQueryInput、QueryBus、AsyncQueryBus
- 上下文感知:ContextAwareBase
- 测试:QueryBusTests、AsyncQueryBusTests、AbstractAsyncQueryTests
graph TB
subgraph "抽象契约"
IQ["IQuery<TResult>"]
IAQ["IAsyncQuery<TResult>"]
IQB["IQueryBus"]
IAQB["IAsyncQueryBus"]
IQIn["IQueryInput"]
ICA["IContextAware"]
end
subgraph "具体实现"
AQ["AbstractQuery<TInput,TResult>"]
AAQ["AbstractAsyncQuery<TInput,TResult>"]
EQI["EmptyQueryInput"]
QB["QueryBus"]
AQB["AsyncQueryBus"]
CAB["ContextAwareBase"]
end
IQ -.实现.-> AQ
IAQ -.实现.-> AAQ
IQB -.调度.-> QB
IAQB -.调度.-> AQB
IQIn -.约束.-> AQ
IQIn -.约束.-> AAQ
ICA -.实现.-> CAB
CAB -.继承.-> AQ
CAB -.继承.-> AAQ
EQI -.实现.-> IQIn
图表来源
- IQuery.cs
- IAsyncQuery.cs
- IQueryBus.cs
- IAsyncQueryBus.cs
- IQueryInput.cs
- IContextAware.cs
- AbstractQuery.cs
- AbstractAsyncQuery.cs
- EmptyQueryInput.cs
- QueryBus.cs
- AsyncQueryBus.cs
- ContextAwareBase.cs
章节来源
- AbstractQuery.cs
- AbstractAsyncQuery.cs
- EmptyQueryInput.cs
- QueryBus.cs
- AsyncQueryBus.cs
- IQuery.cs
- IAsyncQuery.cs
- IQueryBus.cs
- IAsyncQueryBus.cs
- IQueryInput.cs
- ContextAwareBase.cs
- IContextAware.cs
核心组件
- 同步查询基类 AbstractQuery<TInput, TResult>
- 设计要点:通过泛型约束 TInput 实现 IQueryInput,封装 Do() 调用 OnDo(input),子类仅需实现 OnDo。
- 生命周期:创建(构造注入 input)、验证(由调用方保证 input 有效)、执行(Do -> OnDo)、结果返回。
- 异步查询基类 AbstractAsyncQuery<TInput, TResult>
- 设计要点:与同步版本一致,但 DoAsync -> OnDoAsync 返回 Task,适合 IO 密集或需要取消的场景。
- 查询输入模型 EmptyQueryInput
- 使用场景:无需任何输入参数的查询;作为占位符实现 IQueryInput。
- 自定义输入类型:实现 IQueryInput 并在查询类中声明对应泛型 TInput。
- 查询总线 QueryBus / AsyncQueryBus
- 职责:接收 IQuery/IAsyncQuery 对象,进行参数校验(非空),转发到查询对象执行并返回结果。
- 同步总线:Send(IQuery) -> query.Do()
- 异步总线:SendAsync(IAsyncQuery) -> query.DoAsync()
章节来源
- AbstractQuery.cs
- AbstractAsyncQuery.cs
- EmptyQueryInput.cs
- QueryBus.cs
- AsyncQueryBus.cs
- IQueryInput.cs
架构概览
查询体系采用“接口契约 + 抽象基类 + 总线分发”的分层设计,确保:
- 契约清晰:IQuery/IAsyncQuery 定义最小可执行能力
- 执行解耦:AbstractQuery/AbstractAsyncQuery 将执行细节留给子类
- 分发统一:QueryBus/AsyncQueryBus 提供集中式入口与基础验证
- 上下文感知:ContextAwareBase 为查询提供架构上下文访问能力
sequenceDiagram
participant Client as "调用方"
participant Bus as "QueryBus/AsyncQueryBus"
participant Q as "IQuery/IAsyncQuery 实现"
participant Impl as "AbstractQuery/AbstractAsyncQuery 子类"
Client->>Bus : "Send/SendAsync(query)"
Bus->>Bus : "参数校验(非空)"
alt 同步
Bus->>Q : "Do()"
Q->>Impl : "OnDo(input)"
Impl-->>Q : "返回 TResult"
Q-->>Bus : "返回 TResult"
Bus-->>Client : "返回 TResult"
else 异步
Bus->>Q : "DoAsync()"
Q->>Impl : "OnDoAsync(input)"
Impl-->>Q : "返回 Task<TResult>"
Q-->>Bus : "返回 Task<TResult>"
Bus-->>Client : "返回 Task<TResult>"
end
图表来源
详细组件分析
接口契约与实现要求
- IQuery
- 方法:Do() -> TResult
- 实现要求:提供确定性、无副作用或受控副作用的纯查询逻辑
- IAsyncQuery
- 方法:DoAsync() -> Task
- 实现要求:避免阻塞,支持取消与超时;错误应直接传播
- IQueryBus / IAsyncQueryBus
- 方法:Send/SendAsync 接收 IQuery/IAsyncQuery,返回 TResult/Task
- 实现要求:必须进行非空校验;其余交由查询对象处理
章节来源
抽象基类设计与实现细节
- AbstractQuery<TInput, TResult>
- 构造:接收 TInput input(实现 IQueryInput)
- Do() -> OnDo(input);子类仅实现 OnDo
- 适用场景:CPU 密集或内存内数据查询
- AbstractAsyncQuery<TInput, TResult>
- 构造:接收 TInput input(实现 IQueryInput)
- DoAsync() -> OnDoAsync(input);子类仅实现 OnDoAsync
- 适用场景:IO 操作、网络请求、可取消任务
classDiagram
class IContextAware {
+SetContext(context)
+GetContext() IArchitectureContext
}
class ContextAwareBase {
-Context : IArchitectureContext?
+SetContext(context)
+GetContext() IArchitectureContext
#OnContextReady()
}
class IQuery~TResult~ {
+Do() TResult
}
class AbstractQuery~TInput,TResult~ {
+Do() TResult
#OnDo(input : TInput) TResult
}
class IAsyncQuery~TResult~ {
+DoAsync() Task~TResult~
}
class AbstractAsyncQuery~TInput,TResult~ {
+DoAsync() Task~TResult~
#OnDoAsync(input : TInput) Task~TResult~
}
IContextAware <|.. ContextAwareBase
ContextAwareBase <|-- AbstractQuery~TInput,TResult~
ContextAwareBase <|-- AbstractAsyncQuery~TInput,TResult~
IQuery~TResult~ <|.. AbstractQuery~TInput,TResult~
IAsyncQuery~TResult~ <|.. AbstractAsyncQuery~TInput,TResult~
图表来源
- ContextAwareBase.cs
- AbstractQuery.cs
- AbstractAsyncQuery.cs
- IContextAware.cs
- IQuery.cs
- IAsyncQuery.cs
章节来源
查询输入模型设计模式
- EmptyQueryInput
- 作用:实现 IQueryInput,作为“无输入”查询的占位符
- 使用建议:当查询完全依赖上下文或全局状态时,避免冗余输入参数
- 自定义输入类型
- 步骤:实现 IQueryInput;在查询类中声明为泛型 TInput;在构造函数中注入
- 注意:输入应尽量轻量、不可变、可序列化(便于日志与调试)
章节来源
查询生命周期管理
- 创建:构造 AbstractQuery/AbstractAsyncQuery 时注入 TInput
- 验证:总线层对 query 进行非空校验;输入参数的有效性由子类 OnDo/OnDoAsync 内部处理
- 执行:同步 Do() 或异步 DoAsync();内部委托给 OnDo/OnDoAsync
- 结果处理:返回 TResult 或 Task;异常直接传播
flowchart TD
Start(["开始"]) --> NewQuery["创建查询实例<br/>注入输入参数"]
NewQuery --> Validate["总线层参数校验(非空)"]
Validate --> Exec{"同步还是异步?"}
Exec --> |同步| Do["调用 Do()"]
Exec --> |异步| DoAsync["调用 DoAsync()"]
Do --> OnDo["调用 OnDo(input)"]
DoAsync --> OnDoAsync["调用 OnDoAsync(input)"]
OnDo --> Result["返回 TResult"]
OnDoAsync --> TaskRes["返回 Task<TResult>"]
Result --> End(["结束"])
TaskRes --> End
图表来源
章节来源
继承与扩展示例
- 同步查询示例(来自测试)
- 输入:TestQueryInput(实现 IQueryInput)
- 查询:TestQuery(继承 AbstractQuery<TestQueryInput, int>)
- 实现:重写 OnDo,返回 input.Value * 2
- 异步查询示例(来自测试)
- 输入:TestAsyncQueryInput(实现 IQueryInput)
- 查询:TestAsyncQuery(继承 AbstractAsyncQuery<TestAsyncQueryInput, int>)
- 实现:重写 OnDoAsync,返回 Task.FromResult(input.Value * 2)
- 空输入查询
- 使用 EmptyQueryInput 作为输入,查询内部从上下文或其他来源取值
章节来源
参数验证机制与结果映射策略
- 参数验证
- 总线层:对查询对象进行非空校验(ArgumentNullException)
- 输入层:TInput 必须实现 IQueryInput;具体业务参数有效性由 OnDo/OnDoAsync 内部校验
- 结果映射
- 直接映射:OnDo/OnDoAsync 返回 TResult
- 复杂对象:可返回自定义 DTO 或实体;测试中展示了复杂对象与字符串、布尔等类型的返回
- 异常传播:查询内部抛出的异常由总线层直接传播,便于上层统一处理
章节来源
与架构其他组件的集成
- 上下文感知
- AbstractQuery/AbstractAsyncQuery 继承 ContextAwareBase,可访问 IArchitectureContext
- 通过 IContextAware.SetContext/GetContext 注入与获取上下文
- 与其他总线的协作
- 查询总线与命令总线、事件总线协同工作,遵循统一的“输入-执行-输出”范式
- 可测试性
- 测试覆盖了 Do/DoAsync 调用链、异常传播、多实例独立性、不同返回类型等
章节来源
依赖关系分析
- 抽象层依赖
- IQuery/IAsyncQuery 依赖 IContextAware(同步查询基类间接依赖)
- IQueryBus/IAsyncQueryBus 依赖各自对应的接口
- 实现层依赖
- AbstractQuery/AbstractAsyncQuery 依赖 ContextAwareBase 与 IQueryInput
- QueryBus/AsyncQueryBus 依赖各自接口与查询对象
- 测试依赖
- 测试类依赖具体查询实现与输入类型,验证契约与行为
graph LR
ICA["IContextAware"] --> CAB["ContextAwareBase"]
CAB --> AQ["AbstractQuery"]
CAB --> AAQ["AbstractAsyncQuery"]
IQIn["IQueryInput"] --> AQ
IQIn --> AAQ
IQ["IQuery<TResult>"] --> AQ
IAQ["IAsyncQuery<TResult>"] --> AAQ
IQB["IQueryBus"] --> QB["QueryBus"]
IAQB["IAsyncQueryBus"] --> AQB["AsyncQueryBus"]
图表来源
- IContextAware.cs
- ContextAwareBase.cs
- AbstractQuery.cs
- AbstractAsyncQuery.cs
- IQueryInput.cs
- IQuery.cs
- IAsyncQuery.cs
- IQueryBus.cs
- IAsyncQueryBus.cs
- QueryBus.cs
- AsyncQueryBus.cs
章节来源
- IContextAware.cs
- ContextAwareBase.cs
- AbstractQuery.cs
- AbstractAsyncQuery.cs
- IQueryInput.cs
- IQuery.cs
- IAsyncQuery.cs
- IQueryBus.cs
- IAsyncQueryBus.cs
- QueryBus.cs
- AsyncQueryBus.cs
性能考虑
- 选择同步或异步
- CPU 密集且快速:优先 AbstractQuery,减少异步开销
- IO 密集或可取消:优先 AbstractAsyncQuery,提升吞吐与响应性
- 结果类型
- 尽量使用轻量、不可变的 DTO;避免大对象频繁拷贝
- 总线层校验
- 利用总线层的非空校验,减少重复校验成本
- 缓存策略(建议)
- 对于稳定查询,可在查询内部或上层总线层引入只读缓存(基于输入哈希键)
- 注意缓存失效与一致性,结合事件驱动更新
- 并发与隔离
- 多实例独立性已在测试中验证,避免共享可变状态
故障排查指南
- 常见问题
- 传入空查询对象:总线层会抛出参数异常;请检查构造与注入
- 查询内部异常:异常会直接传播至上层;请在上层捕获并记录
- 上下文未设置:若查询依赖上下文,请确保通过 SetContext 注入
- 定位手段
- 单元测试覆盖了异常路径与多实例行为,可参考测试用例定位问题
- 在 OnDo/OnDoAsync 中增加必要的日志与断言
章节来源
结论
查询基类体系通过清晰的契约、可复用的抽象与统一的总线分发,提供了高内聚、低耦合的查询执行框架。同步与异步基类分别适配不同场景,EmptyQueryInput 与自定义输入类型满足多样化的输入需求。配合上下文感知与严格的生命周期管理,查询体系易于扩展、测试与维护。建议在实际项目中遵循本文最佳实践,结合业务场景选择合适的执行模型与缓存策略。
附录
- 最佳实践
- 明确输入模型:尽量使用 IQueryInput 的强类型输入,避免魔法参数
- 控制副作用:查询应尽量无副作用或受控;必要时通过命令总线分离
- 异常处理:在总线层统一捕获与记录,查询内部抛出语义化异常
- 可测试性:为查询编写单元测试,覆盖正常路径、异常路径与边界条件
- 性能优化
- 选择合适基类:根据任务特性选择同步或异步
- 结果建模:使用不可变、轻量的数据结构
- 缓存:对稳定查询引入只读缓存,注意一致性
- 集成建议
- 与事件总线、命令总线协同,形成完整的 CQRS/事件驱动架构
- 通过上下文注入访问服务与配置,避免硬编码