DDD工程结构说明
文档
本工程采用DDD的架构风格,经过组内DDD实践的沉淀形成的工程规范 DDD实践的参考文档详见:
工程结构:
--client/
|-- src
|----|-- main
|----|----|-- java
|----|----|----|-- com.sankuai.crayfish.xxxx
|----|----|----|----|-- service -- thrift服务
|----|----|----|----|-- model -- thrift对象定义
--server/
|-- deploy
|-- src
|----|-- main
|----|----|-- java
|----|----|----|-- com.sankuai.crayfish.xxxx
|----|----|----|-- application -- 应用层
|----|----|----|----|-- service -- 应用服务
|----|----|----|----|-- factory -- 对象转换工程(非必须)
|----|----|----|----|-- validator -- 应用层参数校验(非必须)
|----|----|----|-- domain -- 领域层
|----|----|----|----|-- aggragate -- 聚合层
|----|----|----|----|-- convertor -- 对象转换(非必须)
|----|----|----|----|-- entity -- 实体
|----|----|----|----|-- event -- 领域事件(非必须)
|----|----|----|----|-- repository -- 资源库行为
|----|----|----|----|-- service -- 领域服务
|----|----|----|----|-- valueobj -- 值对象
|----|----|----|---| remote -- 远程调用接口申明(Interface)
|----|----|----|-- infrustructure -- 基础设施层
|----|----|----|----|-- annotation -- 注解
|----|----|----|----|-- cache -- 缓存配置
|----|----|----|----|-- common -- 公共目录
|----|----|----|----|-- config -- 通用配置
|----|----|----|----|-- mafka -- mq配置
|----|----|----|----|-- http -- http接口
|----|----|----|----|-- thrift -- thrift接口
|----|----|----|----|-- repository -- 资源库
|----|----|----|----|----|-- impl -- 资源库实现
|----|----|----|----|----|----|-- convertor -- 对象转换(非必须)
|----|----|----|----|----|-- persist -- 持久化
|----|----|----|----|----|----|-- mapper -- 数据库mapper
|----|----|----|----|----|----|-- model -- DO对象
|----|----|----|----|-- remote -- 远程调用(实现)
|----|----|----|----|----| impl -- 远程调用(接口实现)
|----|----|----|----|----| model -- 远程调用(thrift层对象申明)
|----|----|----|----|-- util -- 对象转换
|----|----|----|-- Application.java(启动类)
|----|----|-- resources -- 资源
|----|----|----|-- mabatis -- db配置
|----|----|----|-- spring -- spring配置
|----|----|----|-- application.properties -- 配置文件
|----|----|-- profiles
下面针对每层进行说明:
应用层
应用服务是领域模型的直接客户,应用层要尽量简单,不包含业务规则或者知识,而只为下一层(指领域层)中的领域对象协调任务,分配工作,使它们互相协作。
领域层提供了细粒度的领域模型对象,不利于它的客户端调用。因此,“基于 KISS(Keep It Simple and Stupid)原则或最小知识原则,我们希望调用者了解的知识越少越好,调用变得越简单越好,这就需要引入一个间接的层来封装。这就是应用层存在的主要意义
目录说明
【service】放置应用层服务
【factory】放置应用层对象转换的工厂,非必须
,有些情况下不需要对象转换的工厂
【validator】应用层参数校验逻辑的放置目录,`非必须,有些情况下不需要参数校验,参数校验应该遵循约定,具体参考实践文档
开发规约:
1.【强制】禁止在应用层写任何领域逻辑,仅负责协调领域模型对象,通过它们的领域能力来组合完成一个完整的应用目标
2.【强制】与横切关注点相关的内容应该放在应用层
3.【强制】thrift接口参数校验属于横切关注点,应该放在应用服务来做
领域层
DDD架构风格的核心层,领域逻辑的主要载体
aggregate 聚合
Eric Evans 阐释了何谓聚合模式:“将实体和值对象划分为聚合并围绕着聚合定义边界。选择一个实体作为每个聚合的根,并允许外部对象仅能持有聚合根的引用。作为一个整体来定义聚合的属性和不变量(Invariants),并将执行职责(Enforcement Responsibility)赋予聚合根或指定的框架机制。”
entity 实体
实体有自己的生命周期,他的生命周期从属于聚合根。能够以主体类型的形式表达领域逻辑中具有个性特征的概念,而这个主体的状态在相当长一段时间内会持续地变化,因此需要有一个身份标识(Identity) 来标记它。
一个典型的实体应该具备三个要素:
- 身份标识
- 属性
- 领域行为
规约
1.【强制】实体对象的命名以Entity结尾。比如UserEntity、CompanyEntity
valueobj 值对象
值类型用于度量和描述事物,是否拥有唯一的身份标识才是实体与值对象的根本区别
规约
1.【强制】值对象的命名规则为 name + Value
event 领域事件
发生在领域中的一些事件,将领域中所发生的活动建模成一系列的离散事件,每个事件都用领域对象来表示,领域事件是领域模型的组成部分,表示领域中过去发生的事情。
remote 远程调用
领域层remote只放置rpc接口的申明,具体实现放在基础设施层
service 领域服务
领域服务(Domain Service)代表了在名词世界(面向对象)中对动词的封装(接口),它封装了领域行为。表示一个无状态的操作
前提在于,这一领域行为在实体或值对象中找不到容身之处。换言之,当我们针对领域行为建模时,需要优先考虑使用值对象和实体来封装领域行为,只有确定无法寻觅到合适的对象来承担时,才将该行为建模为领域服务的方法。
repository 资源库
只定义Interface,代表了一种行为,实现放在基础设施层
convertor 转换器
非必须,如果需要这样的逻辑,放在转换器里
基础设施层
基础设施的职责是为应用程序的其他部分提供技术支持。
Http http接口
Thrift thrift接口
Config 通用配置
Repository 资源库
Remote Rpc调用实现
--|【impl】 Rpc调用实现
--|【model】Rpc调用需要的对象
--|【impl】领域层定义资源库行为的实现
--|---|--【convertor】领域层对象和持久层对象的转换服务 -- 非必须
--|【persist】持久层mapper、DO
Cache 缓存配置
Annotation 注解
Mafka mq配置