业务案例:客服在业务后台审核订单
如果以DDD的风格,如何将上述业务落地?
1、直接操作order对象,order.Audit() 这是最简单明了的方式;
2、领域中引入客服/操作员的概念,operator.Audit(order),然后以领域事件的方式去更改order状态;
我目前的认识是,系统使用者是以上帝模式进入领域,驱动领域模型完成某些活动,即方式1。但方式2看上去更符合实际业务场景,因为订单毕竟是“审核”行为的客体。但如果又一个需求说,要在系统中跑一个job,超过24小时的订单自动审核成功,此时“审核”行为的驱动者又是谁呢?
1. “客服在业务后台审核订单”,这个是一个用例,客服是系统的使用者,也是行为的驱动者;
2. 所有用例都是对应到DDD中的应用层;所以,我们可以在应用层设计一个AuditOrder的方法,这个方法对应上面的user case;
3. AuditOrder方法内,通知Order聚合根做审核订单的业务逻辑;与其说是审核订单,不如说是通知订单将自己的状态变为已审核;因为审核订单的说法,这个行为的触发者应该是系统中的某个账号,账号审核订单,才是合理的;所以当我们调用order.Audit()时,实际上是账号在通知order将自己的状态变为已审核;再比如order.Close(),也是一样的道理,是账号通知订单关闭自己;order的一切行为只关心对自己如何操作;order.Audit(), order.Close()这些行为都是订单允许外部使用的一些操作行为;然后应用层(app layer)会调用领域层订单的这些方法,完成整个用例场景;
4. 关于假如订单是由某个定时job自动触发审核动作的,那此时,order.Audit()的触发者就是这个job了。job通知订单将自己的状态变为已审核与账号通知订单的状态变为已审核,这是两个不同的业务用例场景(user case),但对领域来说都是一样的,因为最后都是通知订单将自己的状态变为已审核;
5. 关于operator.Audit(order)这样的思路,完全是以用户为中心的思路了,不是DDD的做法(大部分人都会犯这样的错误)。这种思路是把应用层的行为等同于人的行为了;人是系统的使用者,user case的触发者;AuditOrder是一个user case,operation最多是这个泳衣的参与者。所以,正确的做法是:order app service里,有一个AuditOrder的面向用例的方法,方法内部,调用order.Audit()领域方法;
感谢这么细致的解答!
goooooooooooooooooood!
按照 2 的话,你需要增加一个虚拟的客服/操作员,这个不冲突,因为在系统运行时,其中的所有 operator 实例都是虚拟的,它们有,或者没有,或者有多个现实的投影。
但是,我觉得这不是解决这个问题的出发点。