应用层代码
应用层包括:应用服务、DTO以及事件发布相关代码。在LeaveApplicationService类内实现与聚合相关的应用服务,在LoginApplicationService封装外部微服务认证和权限的应用服务。
如果应用服务逻辑复杂的话,一个应用服务就可以构建一个类,这样可以避免一个类的代码过于庞大,不利于维护。
领域层代码
请假微服务领域层包含请假和人员两个聚合。人员和请假代码都放在各自的聚合所在目录结构的代码包中。如果随着业务发展,人员相关功能需要从请假微服务中拆分出来,我们只需将人员聚合代码包稍加改造,独立部署,即可快速发布为人员微服务。到这里,微服务内的领域对象,分层以及依赖关系就梳理清晰了。微服务的总体架构和代码模型也基本搭建完成了。
后续工作
详细设计
在完成领域模型和微服务设计后,我们还需要对微服务进行详细的设计。主要设计以下内容:实体属性、数据库表和字段、实体与数据库表映射、服务参数规约及功能实现等。
代码开发和测试
开发人员只需要按照详细的设计文档和功能要求,找到业务功能对应的代码位置,完成代码开发就可以了。代码开发完成后,开发人员要编写单元测试用例,基于挡板模拟依赖对象完成服务测试。
总结
DDD战略设计从事件风暴开始,然后我们要找出实体等领域对象,找出聚合根构建聚合,划分限界上下文,建立领域模型。
战术设计从事件风暴的命令开始,识别和设计服务,建立各层服务的依赖关系,设计微服务内的实体和值对象,找出微服务中所有的领域对象,并建立领域对象与代码对象的映射关系。
FAQ
CQRS其实就是读写分离,主要解决DDD的复杂查询问题。一般是写库和读库分离,但是实效性不容易保证。其实你也可以在同一个库,用领域或者应用查询服务来完成复杂查询的。
- 推广活动为一个聚合,直播推广为一个聚合,但是这两个聚合之间又是有联系的,比如直播推广可以参与推广活动。那这样这个命令到底属于哪个聚合呢?还是说将推广活动作为一个值对象呢
聚合内有实体吧,看看这些实体跟那个聚合根关联紧密,生命周期归聚合根管理,就放在跟聚合根在一起的聚合内,如果别的聚合要用,有两种方案,第一种是通过聚合根引用实体。第二种方案,在另外的聚合内将这个实体设计为值对象或者实体,值对象或实体的数据来源于另外的那个聚合的实体。
关于ddd读写那块,我最近看到有的文章说在ddd化为微服务中最好做到读写分离,将读的逻辑放在service(domain层的),写和其他的逻辑放在entity中,但这里会遇到spring di问题,entity不方便做di,我看的两种方法一种是通过entity的工厂类来实现实体的di,另一种是同一用repository工程类来注入。是否还有更好的方法,还有这种读写是否适合ddd(因为我自己适着用充血模型来写也发现很多时候复杂的读逻辑不适合放在entity中实现)
复杂的查询建议独立出来,通过CQRS来实现,可以根据时效性要求设计为读写同一个库或者读写库分离的方式,复杂的查询逻辑可以独立为应用或者领域服务。复杂聚合的实体初始化建议用工厂类服务,简单的直接用构造函数就可以了。
请假单在请假聚合里,审批人在人员组织关系聚合里,在请假单聚合根(leave.java)会关联人员聚合的人,然后导航到审批人。
“DO 是实体和值对象的数据和业务行为载体,承载着基础的核心业务逻辑。通过 DO 和 PO 转换,我们可以完成数据持久化和初始化。”“第二步:提交审批facde实现DTO转DO”一直不理解不了DO对象,老师,你可以结合这章的内容,代码说明下DO对象吗?这个DO对象应该放在项目结构哪个目录下?
这个DO对象是领域模型的实体对象,放在Entity目录下。DTO转DO是将外部请求数据转换为领域模型的实体对象。
审批规则值对象有查询审批规则方法?不应该通过领域服务或聚合根做查询吗?这里的值对象是充血模型?
审批规则有两个:
审批规则的配置数据,独立存在
保存在请假单上的审批规则,它根据请假基本信息匹配审批规则配置数据后获得,只要请假基础数据不变,你就不需要在每次提交审批的时候去查询审批规则的配置数据。依附于请假单的这个审批规则是值对象。
组织关系是一个实体,记录人员关系和上级领导,上级领导数据来源于人员聚合根,所以设计为值对象。
一般通过聚合根来调仓储服务。用仓储服务来实现数据的初始化和持久化。大批量的数据查询建议用CQRS模式。
“提交下一步审批”这一步是不是不应该这样,是不是根据“审批”业务流,产生的审批事件自动决定是到最后一步了,还是继续下一步审批,因为审批人只需要关心自己的审批就可以了,不要关心是否还有一下审批人(也就是不需要点击“发往下一个审批人”),也样流程更合理?
这个是系统内部判断的,根据审批规则和当前审批人的角色来确定是否还有下一审批,如果有则获取下一审批人和角色,给请假单分配下一审批人
有时候为了完成领域层的业务设计,有的实体对内部属性的访问进行了控制,但是在仓储接口存储的时候又需要持久化下来,这时候该怎么做呢?
把DO实体传给仓储接口即可,仓储实现内部会将DO映射成PO对象,然后PO对象就可以实现持久化。
如果我要对审批规则做增删改,怎么设计比较合理?在请假领域里新增一个LeaveApproveRuleService,里面加上增删改的方法,可以吗?(传统方式)
可以。不必纠结聚合根。聚合根目的是保证聚合内的数据一致性。审批规则内不会出现这种请假。可以用领域服务或实体的方法。
一个人可能会有多级组织关系,比如项目经理,处室领导,部门领导。中间还会查询过滤,所以设计为实体。