在Domain Aggregate方法调用中使用装饰器实现DI的方案是否合理?
方案整体合理性评估
这个实现方案核心思路是完全可行的,在DDD架构实践里属于很规范的解耦思路,有几个明显的设计优势:
- 严格遵循了聚合的单一职责原则:你把映射、外部接口调用、持久化这些非领域逻辑全部剥离到装饰器层,聚合只负责维护自身状态、执行业务规则,不会被基础设施相关的代码污染,也避免了聚合需要注入大量外部依赖的问题。
- 装饰器链管控流程符合开闭原则:后续需要新增流程节点(比如幂等校验、操作审计、调用重试)只需要新增对应装饰器插入链中即可,不需要修改原有业务逻辑和聚合代码。
- 依赖注入的实现很干净:通过装饰器的构造函数注入所有基础设施依赖,再将必要的参数和依赖传入聚合方法,既没有用侵入性极强的属性注入,也没有让聚合的构造函数变得臃肿,完美规避了你提到的两个问题。
可优化的细节点
现有方案已经可以正常运行,下面的调整只是为了进一步降低耦合,让领域层更纯净,不做也不会影响业务正确性:
- 移除聚合中对持久化逻辑的感知
你现在聚合的Save方法中直接调用了ISavePaymentCommand.Execute,相当于聚合知道持久化层的存在,不符合DDD中聚合不感知存储的设计原则。可以调整为:
- 聚合单独暴露
SanitiseCard公共方法,只负责执行卡片脱敏的业务逻辑 - 持久化逻辑全部放到对应的存储装饰器中,在装饰器内判断
AcquirerResponse.IsSuccessful再决定是否调用存储命令
调整后聚合完全不需要知道持久化相关的接口和逻辑,领域层和基础设施层的耦合会更低。
- 调整装饰器和聚合的调用关系
你现在的调用方式是payment.Capture(_paymentCaptureDecorator),相当于聚合需要知道装饰器的存在,耦合了外层的流程管控逻辑。可以调整为装饰器链作为流程入口,聚合作为参数传入:
var payment = _mapper.Map<Payment>(request); var response = await _paymentCaptureDecorator.Execute(payment);
调整后聚合完全不需要依赖任何外层逻辑的接口,彻底回归纯业务规则载体的定位。
- 可选优化:复用通用映射逻辑
如果多个装饰器中存在相同的映射逻辑,可以单独抽离为通用的映射器类,避免重复代码,当前放在装饰器内也符合单一职责要求,没有问题。
总结
你的核心设计思路没有问题,是非常合理的领域层解耦实践,上述优化点只是细节层面的打磨,就算不调整也完全可以支撑业务迭代。
内容的提问来源于stack exchange,提问作者Dr Schizo
相关产品推荐
相关产品推荐

