一、DDD领域驱动设计
1、DDD是一种设计思想,领域即业务,业务驱动设计,直接将业务映射到代码中。
2、DDD的设计始于领域的划分,一个项目可以划分为多个子域,并可以按功能划分为核心域、非核心域、支撑域。
3、确定领域后,就要对领域内的对象进行建模,抽象出领域模型,并用领域模型驱动项目的开发。
4、DDD的诞生早于微服务,但DDD是指导微服务架构设计的强有力思想。
二、DDD分层实践
1、领域层:实现领域的核心业务逻辑。
2、应用层:基于领域的应用程序用例,可能存在多个应用程序对应于一个领域层。
3、展示层:基于应用程序的UI,WebAPI也是UI层的一种。
4、基础层:提供EFCore等基础设施的支持。
三、DDD的基本构件:主要位于领域层和应用层
1、领域层构件
- 实体(Entity):拥有唯一标识符的对象,实体的其它属性会经历各种变化,但标识符是不变的。具体实践中,实体一般表现为EFcore中的实体类,实体类的Id属性就是标识符,只要Id不变,就是指同一个对象。
- 值对象(ValueObject):没有标识符的对象,有多个属性,全部属性相同时才视为同一个对象。依附于实体存在,主要用于表示一个整体性的属性组合,如一个经纬度位置。
- 聚合和聚合根(Aggregate&AggregateRoot):一个系统中会有多个实体(包括值对象),可以将关系紧密的实体类放到一个聚合中,每个聚合中有一个实体作为聚合根,所有对聚合内实体的访问都通过聚合根进行,外部系统只能持有对聚合根的引用。聚合根即是实体类,也是所有聚合内实体的管理者。聚合体现了整体和部分的关系,且有相同的生命周期。如订单和订单明细,删除了订单,订单明细也就消失,而外部系统不能直接引用订单明细,只能引用订单,对订单明细的操作都通过订单来进行。
- 仓储(接口)(Repository):将数据访问层抽象出来,隐藏了底层对数据源的CRUD操作,被领域层和应用层用来访问数据库。仓储接口位于领域层,仓储实现位于基础设施层。
- 规约(Specifation):实体对象的过滤器,可重要、可组合。
- 领域服务(DomainService):聚合根中可以实现聚合内的业务逻辑(充血模型)。但是,当聚合内的业务逻辑需要注入外部服务或仓储时,或者需要实现跨聚合业务逻辑时,应该将业务逻辑抽出,通过领域服务来实现。
- 领域事件(DomainEvent):一种低耦合的事件订阅和通知方式,实现了开闭原则。聚合类一般不需要事件,同一个微服务中聚合之间的事件传递,通过领域事件实现。如果需要跨微服务实现事件通知机制,则通过集成事件来实现。
2、应用层构件:
- 应用服务(ApplicationService):应用程序用例的业务逻辑,通常与外部系统交互,获取和返回数据传输对象。业务逻辑是放在领域服务,还是应用服务中,并不好确认,如果多个应用程序用例,重复使用同一个业务逻辑,应该考虑将这个业务逻辑移入领域服务。
- 数据传输对象(DTO):DTO是贫血对象,不包含任何业务逻辑,只用于应用层和展示层的数据传递。
- 工作单元(UOW):聚合内数据操作的关系是非常紧密的,要保证事务的强一致性。聚合间的协作关系不紧密,保证事务的最终一致性即可。对数据库的若干相关联操作,应组成一个工作单元,在工作单元中的操作统一提交,要么全部成功,要么失败全部回滚。