DDD领域设计架构实践

苦逼的程序员,笔者在写这篇文章时还在加班,希望今天能够早点回家

DDD领域设计模型是几年前开始流行,大概在最近笔者开始接触领域设计模型,并逐步在项目中开始应用。

1)领域设计模型的应用原则:根据大神指点,领域设计模型只关注核心域,在DDD中除了核心域还有通用域和支撑域。举个例子,笔者所在项目是保险投保系统,涉及的流程有:投保,核保,保费计算,缴费,出单。当然,首先要有产品工厂,所谓的产品工厂就是规范能买什么样的保单,对里面的标的,责任,条款,免赔,特别约定进行组合。其中缴费和产品工厂笔者认为就不属于核心域。因为缴费对于投保系统来说,不属于必须且独有的流程,并且对于支付来说,投保和支付完全是两个领域,只是投保部分流程用到了支付。另外就是产品工厂,对于外围投保系统来说,每个保险公司都有多套外围投保系统。但是产品必须有产品工厂来支持,所以产品工厂对于投保来说也不是核心域。其实这也是一种工作方式,将大部分精力放到核心问题上。

DDD领域设计架构实践_微服务

2)DDD与微服务的关系:

1)对于微服务架构,笔者强调一个原则,就是微服务间数据库表不能共享,数据交互需通过微服务间调用进行。

2)同时,每个领域与微服务之间最好是1对1关系,当然根据实际情况,也可以是多个领域放在一个微服务中,但是不要一个微服务中方多个领域。举个栗子,比如投保系统找那个的投保涉及到保单信息填写,各种代理信息和经办信息校验。可以认为是一个领域。可以单独微服务,但是不要将投保和核保放在同一个微服务中。

DDD领域设计架构实践_业务逻辑_02

3)微服务内,如何基于DDD进行构建服务,这里不得不提另外一个概念,六边形架构。笔者查阅过相关资料,对于六边形架构解释都比较抽象。笔者总结下来,就是基于六边形架构。系统更加健壮。后面笔者会举例进行说明。

对于传统应用,主流分层方式为三层架构,主要有controller ,service,dao ,对于这种传统三层架构,其实也是有市场的,具体表现在,如果说数据库表结构比较简单,关联少,业务逻辑简单的系统,那还是比较爽的。迭代速度快,基于orm框架,和一些自动化生成的工具,可以生成大部分代码。其实这在DDD中就是贫血模型。

3)相比于传统三层架构,DDD最大特点是分为四层架构,web,application,domain,infrastructure.

DDD模型,分包情况详细说明

DDD领域设计架构实践_业务逻辑_03

关于各层说说明:

facade层:该层的主要作用是对前段请求做适配,封装,校验,异常处理,不做业务处理。主要流程是接受参数,封装参数,调用application,返回DTO,仅此而已。关于controller如何划分,我们的做法是根据页面进行划分,比如说投保页面中,有相关经办人校验,保单提交,实名制认证等,那就讲相关接口放到一个controller类中。同时如果业务比较简单,也可以将相关接口放在一个类中,如:投保分为新保和续保,那么都可以放在一个controller中,封装为两个接口。

application层,主要是根据业务流程进行划分,还是以投保为例,新保相关流程作为一个service,续保相关流程作为一个service。如果涉及到公共部分,开抽象出公共接口进行封装。但是笔者不建议这样做。因为两个service的有界上下文不同。接口可能只是看起来相同,实际上含义并不相同,一旦使用继承,那么就会出现随着需求比变动,修改子类还是修改父类的问题。实际上这个也是继承的劣势。

domain层:domain层主要有几个部分组成,1)service类,在DDD中,提倡对象值和对象属性相分离,之前一直不太理解,后来经过学习,其实就是将领域对象行为和属性分离,所有行为都封装到service中,属性封装在entity中,application通过service操作entity属性。

service有两种,一种是单聚合根进行操作,另外就是多个entity交叉操作,具体负责业务规则,可套用设计模式进行处理。

entity类:entity就是领域对象,这里重点说一下聚合根,其实就是主表。比如保险产品信息分为:条款,责任,限额免赔,费率,方案,笔者在实际过程中,以以上几个概念作为聚合根,子表信息放在聚合跟中。在实际使用过程中,会在领域对象与dto之间进行转换,领域对象中最好有单独builder或者factory类,专门用于转化,其中涉及到复杂字段映射,简单字段映射可使用beanutil.copyproperties 复杂字段映射涉及到逻辑转换以及层级关系,可使用mapstruct框架。

infrastructure层,主要负责基础设施,笔者使用基础设施层主要做以下几件事:

1)数据库业务逻辑,在数据库业务逻辑中,建议所有对子表操作,封装到主表中,由主表做接口统一对外提供。有一种简便办法,就是将子表操作封装为对象委托给主表接口,同样实现该功能。

2) 业务逻辑中对缓存的封装

3)对mq封装

4)对调用外部系统封装:这里简单说下防腐层的用法通过底层对远程调用做基础封装,在domain层做防腐层处理。例如通过调用http接口调用远程实名查验接口,可以在infrastructure层做都http接口最基本的封装,非业务封装,然后再在domain层做参数校验以及业务封装。以便用于application层调用。

能看到这里都是真爱,感谢观看,希望能给大家带来启发。同时,文章内容也是笔者学习过来的有不对之处敬请谅解,同时欢迎讨论学习,笔者会对文章进行持续改进。特别推荐殷浩大神的ddd相关文章。