像梦一样奔驰|谈DDD领域驱动设计和建模( 七 )


举一个场景来说 , 根据订单号获取一个聚合复杂对象采购订单 , 对采购订单进行修改后再进行保存 。 这个时候和持久化层存在两次交互 , 第一次是数据的读取 , 第二次是修改后数据的存入 。
对于数据读取 , 到领域层则是Factory需要实例化一个聚合对象并返回应用层 。 而Factory将该工作分解到聚合里美的每一个子实体 , 子实体通过Repository接口获取到ResultSet并进行OR转换后返回 , Factory将拿到的所有实例化对象进行聚合返回一个完整的聚合对象实例 。 对于数据存储 , 仍然应该是Factory接管该操作 , 然后对数据进行分解后分别调用聚合中的每一个实体的仓储接口本身的保存方法 , 对数据进行持久化 , 在Factory层进行完整的事务控制并返回结果 。
领域服务层的构建
像梦一样奔驰|谈DDD领域驱动设计和建模在当前的领域分层架构中没有服务层的概念 , 在领域层和应用层都有服务 , 可以将服务层进一步抽取出来 , 服务层即向应用层提供所有的服务能力 。 这个服务能力不仅仅是原子服务能力 , 也包括了组合服务能力 。 对于服务层提供的服务能力 , 由服务层控制事务 。 对于进一步的服务编排 , 则在应用层进行完成 , 如果完全基于SOA参考架构 , 则在上面还会有BPM或BPEL层 , 重点是对原子服务进行组装和编排 。
在领域建模中的整体思路中 , 我们做两个层面的理解:

  • 其一是领域模型层重点是隔离传统的数据表并抽象为领域对象;
  • 其二将应用层和领域模型层解耦 , 模型层提供的能力是以领域服务的方式暴露 。
对于最贫血的领域服务层 , 就是一个DAL层封装的服务化 , 即只提供数据库表CRUD能力的服务化 , 在这种情况下基本满足所有的业务处理和应用需求 , 但是领域服务层没有任何领域逻辑 , 也没有领域对象的转换 。
而我们这种需要的领域服务主要包括三个方面的内容:
  • 其一是领域对象识别 , 然后将领域对象的类似CRUD操作暴露为服务;
  • 其二是对于核心的业务规则的识别 , 将业务规则识别为业务服务;
  • 其三是组合服务 , 根据业务场景需要将几个原子服务组合为一个更大的服务 。
领域对象我前面已经谈到过 , 领域对象是具有完整相同的生命周期的对象 , 领域对象中的各个子对象不能脱离主对象独立存在 。
如我们经常说的订单 , 合同 , 供应商都是领域对象;但是这些领域对象在后台往往存在多张一对多的数据表 , 如订单至少包括了订单头和订购明细信息等 。
在领域对象识别中必须要首先识别核心的实体对象 , 再根据实体对象的属性需求来识别值对象 , 领域对象识别清楚了再根据业务场景的需求考虑领域对象的能力暴露 。
领域对象中有一个核心就是将数据库表对象转化为领域对象 , 并将领域对象的能力暴露为粗粒度的服务 , 即数据库的CRUD能力转换为了对象的生命周期操作能力 。 但是在这种分析模式下容易遗漏业务规则转换为业务服务部分的能力需求 , 这类业务服务往往需要在对象关联依赖和真实业务场景和用例活动中才能够识别 。
举例来说供应商领域对象开始只识别了供应商的增删改查的对象处理能力;但是在我们做采购订单和合同的时候 , 有一个业务规则是需要校验供应商是否有效?在这种场景下我们需要将这种独立可复用的业务规则转化为业务服务 , 这种业务服务相当多 , 也可复用 , 属于我们经常说的粗粒度服务范畴 。
还有一类是组合服务 , 跟业务流程中的子流程或活动相挂钩 , 如银行转账 , 资产调拨 , 供应商合并 , 单据提交(单据保存+流程启动)等 , 都是典型的组合服务 , 往往需要调用多个原子服务或原子API操作才能够完成 。 这种组合服务能力可以进一步在领域服务层进行封装 。


推荐阅读