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


在引入了领域对象层和领域服务层后 , 需要对传统的分层架构进行调整 。
首先是引入领域对象 , 对原有的数据库表对象进行第一层抽象 , 数据接口转换为对象接口;其次是对原有的展现层和逻辑层进行解耦 , 引入领域服务层 , 在领域服务层需要承载业务逻辑 , 但是又不是完全承载;初步思考的是原有的业务逻辑层的内容有1/3左右划分到应用层;而2/3左右能够下沉到领域服务层 。
领域服务层贫血很多时候可以追溯到原有分层架构中本身的业务逻辑层就贫血 , 业务逻辑层逻辑都放到应用层和数据库存储过程中 , 自然转换到领域建模中也存在贫血的问题 。
领域对象服务中的领域对象本身就是多个数据表的汇聚 , 所有对象服务可以解决对象级的事务问题 , 如订单保存中头和明细的操作严格控制在一个事务里面 。 但是对于领域服务层的组合服务仍可能存在分布式事务的问题 , 在这里还是建议基于BASE模式思路进行操作 。 还有一个方式就是对于组合服务而言 , 不用直接对原子服务进行组合 , 而是对原子服务下层的对象级操作API进行组合 , 这样即方便启用数据库层或逻辑层的事务进行事务控制 。
基于领域驱动思路下业务系统构建
像梦一样奔驰|谈DDD领域驱动设计和建模在前面已经谈到 , 对于贫血的领域层 , 主要体现在两个方面 , 一个是没有领域业务对象的概念(领域模型中的聚合根) , 一个是没有明确的粗粒度的业务规则逻辑处理层 。 在这种情况下 , 原有的业务逻辑层变化为仅仅是DAL层的一个简单封装或通道 , 实际的业务处理全部转化到action层或dal层进行了处理 , 导致无法真正提炼一个业务模块真正应该具备的领域服务能力 。
粗粒度的领域服务提供包括两个方面 , 一个是完整的领域业务对象提供的数据服务 , 一个是处理业务规则和逻辑用的业务服务 。 在领域驱动设计中 , 前者部分在仓储模型中完成 , 后者在service中完成 。 这里要注意DDD里面的service , 和我们基于SOA分析和设计中的服务层仍然还是有差别 , 所有的共性的 , 应该提供给应用层访问的粗粒度的能力都应该抽象为服务层的服务 。
在当前的领域分层架构中没有服务层的概念 , 在领域层和应用层都有服务 , 可以将服务层进一步抽取出来 , 服务层即向应用层提供所有的服务能力 。 这个服务能力不仅仅是原子服务能力 , 也包括了组合服务能力 。 对于服务层提供的服务能力 , 由服务层控制事务 。 对于进一步的服务编排 , 则在应用层进行完成 , 如果完全基于SOA参考架构 , 则在上面还会有BPM或BPEL层 , 重点是对原子服务进行组装和编排 。
实体要考虑两个层面 , 一个是完全的data entity , 一个含操作的entity , 为了考虑在SOA架构中的数据和操作分离 , 建议还是采用完全的data entity实体 , 这个时候这种实体可以进一步作为跨层传输的DTO对象 。 而对于原有的DAO层 , 也不仅仅是实现数据的持久化 , 很多OR-Mapping操作也会在该层完成 。 数据层关注的是数据对象即和数据库一一映射的表 , 而领域层关注的是领域对象(可能涉及多张强聚合的表);数据层最终关心的是数据对象的持久化 , 而领域层关心的是业务对象全生命周期的管理 。
在考虑了数据和操作分离后 , 对于聚合根的业务对象应该有一个专门的业务对象类 , 来处理所有和业务对象属性 , 状态变化相关的操作 , 即控制业务对象完整的数据和生命周期 。 而service类本身不应该对数据进行任何cud操作 , service类的所有操作都应该转入到业务对象类中进行处理 。 在这种模式下service类目的仅仅是处理业务规则和逻辑 , 最终处理结果的落地仍然通过业务对象类来完成 。
业务系统的构建 , 不是简单的横向分层 , 还包括了纵向的分业务模块和业务组件 。 在领域驱动设计里面没有太多的对这两块结合的描述 。 在这里要注意两个方面的内容 , 一个是每一个业务组件都会向上层提供领域服务能力 , 第二每一个业务组件也会向其它业务组件提供领域服务能力 。


推荐阅读