关于DDD与CQRS中commands和queries归属层级的困惑
DDD & CQRS:命令/查询分层的常见疑问解答
两种观点的核心差异
先把两种说法的边界理清楚:
- 观点1:命令(Commands)、查询(Queries)作为业务意图消息,和领域事件(Domain Events)同属领域层;只有对应的处理程序(Handlers)归到应用层
- 观点2:命令/查询本身就属于应用层,处理程序也在这一层
观点1下的调用逻辑
按第一种观点,API/表现层不是绝对不能直接调用命令/查询,但行业里更倾向于通过应用服务封装调用,原因很实际:
- 解耦:避免表现层直接绑定领域层的消息结构,后续领域层调整时,不用改一堆API接口
- 复用横切逻辑:日志、权限校验、事务控制这些通用逻辑,集中在应用服务层处理就行,不用在每个API里重复写
- 适配转换:把HTTP请求这类表现层输入,转成符合领域术语的命令/查询对象,顺便做参数校验、格式修正
命令/查询的存放位置
如果采用观点1的架构,建议这么放:
- 命令:领域层下单独建
commands目录(比如domain/commands/CreateOrderCommand.java),只定义业务操作的意图和必要参数,用领域内的统一术语,别和API的DTO混在一起 - 查询:领域层下建
queries目录(比如domain/queries/GetOrderByIdQuery.cs),明确查询的业务目的(比如“获取用户的待支付订单”而非“查order表where id=?”),同样用领域术语
注意:命令/查询只是纯数据载体,里面不能写任何业务逻辑,所有逻辑都交给应用层的处理程序去实现。
关于复杂度的权衡
观点1确实会多一层结构,增加初期的复杂度,但换回来的好处也很实在:
- 领域模型更完整:命令/查询是业务语言的一部分,放在领域层能让整个领域模型更清晰地表达业务意图
- 复用性更强:同一个命令/查询可以被API、后台定时任务、CLI工具等不同表现层复用,不用重复定义类似的对象
- 测试更方便:单独的命令/查询对象更容易做单元测试,也能更直观地验证业务规则的正确性
内容的提问来源于stack exchange,提问作者Florin S
相关产品推荐
相关产品推荐

