建模方法
- 用例分析法
- 事件风暴法
-
第一步,识别出领域事件和业务规则
截屏2023-09-27 11.21.07.png -
第二步,识别命令和执行者
截屏2023-09-27 11.25.40.png -
第三步,识别领域名词
截屏2023-09-27 11.29.40.png
建立领域模型
主要是要识别领域对象(domain object),领域对象之间的关系,以及领域对象的关键属性,必要的时候还要将领域对象组织成模块。
找到领域实体,描述实体规则,画出实体之间的关系
截屏2023-09-27 14.03.02.png划分模块
很多实体和关联混杂在一起,形成了一个“蜘蛛网”。但人的认知能力是有限的,面对这样一张复杂的对象网络,就产生了认知过载(cognitive overload)。解决这一问题的方法就是“模块化”。也就是说,把模型中的业务概念组织成若干高内聚的模块(module),而模块之间尽量低耦合。
截屏2023-09-27 14.02.47.png按领域模型设计数据库
截屏2023-09-27 14.44.59.png分层架构设计
DDD分层架构.drawio.png代码设计
推荐的分包原则
截屏2023-09-27 15.48.27.png结构化分解
对于复杂的业务流程,可以使用结构化分解让代码有层次更清晰。
截屏2023-09-27 15.52.28.png 截屏2023-09-27 15.52.42.png 截屏2023-09-27 15.53.05.png
“表意接口”(Intention-Revealing Interfaces)模式
- 每个类和方法的命名都应该尽量直观地反映领域知识,与统一语言保持一致。这种做法也是 DDD 的一个模式,叫做 “Intention-Revealing Interfaces”,可以译作表意接口。
-
将领域知识(规则)内聚到领域实体或领域服务中,避免分散在各处的业务代码中,造成领域知识被割裂肢解和代码的业务语义表现弱。
截屏2023-09-27 15.57.29.png
“领域服务”(Domain Service)模式
- 领域的规则校验器xxxValidator,也叫领域服务
package chapter11.unjuanable.application.orgmng;
// imports...
@Service
public class OrgService {
private final OrgValidator validator; //代替了原来多个 Repository
private final OrgRepository orgRepository;
@Autowired
public OrgService(OrgValidator validator
, OrgRepository orgRepository) {
// 为依赖注入赋值...
}
public OrgDto addOrg(OrgDto request,Long userId) {
validator.validate(request); // 代替原来的 validate() 方法调用
Org org = buildOrg(request, userId);
org = orgRepository.save(org);
return buildOrgDto(org);
}
private OrgDto buildOrgDto(Org org) {
//将领域对象转成DTO...
}
private Org buildOrg(OrgDto request, Long userId) {
//将DTO转成领域对象...
}
- 领域依赖的处理器xxxHandler,也叫领域服务
package chapter12.unjuanable.application.orgmng;
// imports ...
@Service
public class OrgService {
private final OrgBuilderFactory orgBuilderFactory;
private final OrgRepository orgRepository;
private final OrgHandler orgHandler; //新增了一个领域服务依赖
@Autowired
public OrgService(OrgBuilderFactory orgBuilderFactory
, OrgHandler orgHandler
, OrgRepository orgRepository) {
// 为依赖注入赋值 ...
}
@Transactional
public OrgDto addOrg(OrgDto request,Long userId) {
// 添加组织的功能已完成,这里省略 ...
}
//修改组织基本信息
@Transactional
public OrgDto updateOrgBasic(Long id, OrgDto request, Long userId) {
Org org = orgRepository.findById(request.getTenant(), id)
.orElseThrow(() -> {
throw new BusinessException("要修改的组织(id ="
+ id + " )不存在!");
});
orgHandler.updateBasic(org, request.getName()
, request.getLeader(), userId);
orgRepository.update(org);
return buildOrgDto(org);
}
//取消组织
@Transactional
public Long cancelOrg(Long id, Long tenant, Long userId) {
Org org = orgRepository.findById(tenant, id)
.orElseThrow(() -> {
throw new BusinessException("要取消的组织(id ="
+ id + " )不存在!");
});
orgHandler.cancel(org, userId);
orgRepository.update(org);
return org.getId();
}
private static OrgDto buildOrgDto(Org org) {
// 将领域对象转换成DTO
}
}
“工厂”(Factory)模式
DDD 认为,领域对象的创建逻辑也是领域层的一部分。如果创建领域对象的逻辑比较简单,可以直接用对象的构造器来实现。但是如果比较复杂,就应该把创建逻辑放到一个专门的机制里,来保证领域对象的简洁和聚焦。这里说的专门机制可以是一个方法或者一个类,可以有很多种实现方式。不论具体方式是什么,在 DDD 里统称为工厂(Factory)模式。
通常,领域对象的工厂放置在domain层,到时对象构建的入参基本上来自application层的参数。如何既保持层间依赖原则,又不新增中间对象,我们可以借助Builder模式来实现对象的构建。
package chapter11.unjuanable.domain.orgmng;
// import...
public class OrgBuilder {
//用到的 validator
private final CommonValidator commonValidator;
private final OrgTypeValidator orgTypeValidator;
private final SuperiorValidator superiorValidator;
private final OrgNameValidator orgNameValidator;
private final OrgLeaderValidator orgLeaderValidator;
//用这些属性保存创建对象用到的参数
private Long tenantId;
private Long superiorId;
private String orgTypeCode;
private Long leaderId;
private String name;
private Long createdBy;
public OrgBuilder(CommonValidator commonValidator
, OrgTypeValidator orgTypeValidator
, SuperiorValidator superiorValidator
, OrgNameValidator orgNameValidator
, OrgLeaderValidator orgLeaderValidator) {
//注入各个 Validator...
}
// 为builder 的 tenant 属性赋值,然后返回自己,以便实现链式调用
public OrgBuilder tenantId(Long tenantId) {
this.tenantId = tenantId;
return this;
}
// 其他5个属性赋值与 tenantId 类似 ...
public Org build() {
validate();
Org org = new Org();
org.setOrgTypeCode(this.orgTypeCode);
org.setLeaderId(this.leaderIc);
org.setName(this.name);
org.setSuperiorId(this.superiorId);
org.setTenantId(this.tenantId);
org.setCreatedBy(this.createdBy);
org.setCreatedAt(LocalDateTime.now());
return org;
}
private void validate() {
commonValidator.tenantShouldValid(tenantId);
orgTypeValidator.verify(tenantId, orgTypeCode);
superiorValidator.verify(tenantId, superiorId, orgTypeCode);
orgLeaderValidator.verify(tenantId, leaderId);
orgNameValidator.verify(tenantId, name, superiorId);
}
}
本文主要参考
钟敬老师的《手把手教你落地 DDD》
张建飞老师的《基于DDD的应用架构设计和实践》
网友评论