DDD案例(2):从领域分析到代码实现(8)

简介: DDD案例(2):从领域分析到代码实现(8)

梳理之后的领域设计类图非常规范。除了合成关系,存在OO聚合关系的实体都分到不同的聚合中,更不用说完全独立的Backlist实体。如果多个聚合边界的实体依赖了相同的值对象,可以定义多个相同的值对象,然后将它们放到各自的聚合边界内。分解关系薄弱处确定的聚合边界如图20-55所示。


image.png


考虑聚合设计原则,由于Learning聚合中的Course实体具有独立性,因此需要对图20-55稍做调整,将Course实体分离出来,定义为单独的聚合。除此之外,其余聚合边界都是合理的,不需再做调整。最终,确定了聚合边界的领域设计类图如图20-56所示。

由此得到的聚合包括:

qTraining聚合;

qCourse聚合;

qLearning聚合;

qTicket聚合;

qTicketHistory聚合;

qFilter聚合;

qValidDate聚合;

qValidDateAction聚合;

qCancellingAction聚合;

qCandidate聚合;

qAttendance聚合;

qBlacklist聚合。


image.png


即使在领域设计模型中,我们也无须为领域模型对象定义字段。每个聚合内的实体或值对象到底需要定义哪些字段,可以结合业务服务,通过测试驱动开发逐步驱动出来。领域设计类图最重要的要素是聚合。一旦确定了聚合,实际上也就确定了管理聚合生命周期的资源库。至于需要哪些领域服务和其他角色构造型,可以交由服务驱动设计来识别。

2)服务驱动设计

驱动设计的起点是业务服务。以提名候选人业务服务为例,将业务服务规约的基本流程转换为由动词短语组成的任务,然后通过向上归纳和向下分解获得由组合任务与原子任务组成的任务树:

q提名候选人(业务服务)

♦   确定候选人是否已经参加过该课程

○   获取该培训对应的课程

○   确定课程学习记录是否有该候选人

♦   如果未参加,则提名候选人

○   获得培训票

○   提名

○   保存票的状态

♦   发送提名通知

○   获取通知邮件模板

○   组装提名通知内容

○   发送通知

结合任务分解与角色构造型,它的序列图脚本如下:

 

NominationAppService.nominate(nominationRequest) {

  LearningService.beLearned(candidateId, trainingId) {

     TrainingRepository.trainingOf(trainingId);

     LearningRepository.isExist(candidateId, courseId);

  }

  TicketService.nominate(ticketId, candidate) {

     TicketRepository.ticketOf(ticketId);

     Ticket.nominate(candidate);

     TicketRepository.update(ticket);

  }

  NotificationService.notifyNominee(ticket, nominee) {

     MailTemplateRepository.templateOf(templateType);

     MailTemplate.compose(ticket, nominee);

     NotificationClient.notify(notificationRequest);

  }

}

 

该序列图脚本对应的序列图如图20-57所示。

20-57中的NominationAppService应用服务承担了多个领域服务之间的协作职责,且需要根据beAttend()方法的返回结果决定提名的执行流程。这实际上属于领域逻辑的一部分,故而应该在NominationAppService应用服务内部引入一个领域服务来封装这些业务逻辑。新增的领域服务为NominationService修改后的序列图如图20-58所示。


image.png

image.png

image.png

image.pngimage.png


20-58中的MailTemplate是一个聚合,存储了不同类型操作需要通知的邮件模板。在前面的领域分析建模与领域设计建模时,未能发现该聚合。这也印证了领域建模很难一蹴而就,需要不断地迭代更新和演进。

相关文章
|
消息中间件 NoSQL Java
springboot redis 实现消息队列
springboot redis 实现消息队列
1260 1
|
10月前
|
XML Java 测试技术
使用 @Transactional 控制事务边界:传播和隔离解释
本文深入解析了 Spring 框架中的 `@Transactional` 注解,重点介绍了事务管理中的传播行为与隔离级别。内容涵盖事务的基本概念、声明式事务管理、回滚机制、传播模式(如 REQUIRED、REQUIRES_NEW 等)及隔离级别(如 READ_COMMITTED、SERIALIZABLE),并通过示例说明如何在实际开发中灵活应用这些特性,以确保数据一致性与系统性能的平衡。适合 Java 开发人员深入理解 Spring 事务机制。
771 1
使用 @Transactional 控制事务边界:传播和隔离解释
|
11月前
|
消息中间件 Java 数据库
Java 基于 DDD 分层架构实战从基础到精通最新实操全流程指南
本文详解基于Java的领域驱动设计(DDD)分层架构实战,结合Spring Boot 3.x、Spring Data JPA 3.x等最新技术栈,通过电商订单系统案例展示如何构建清晰、可维护的微服务架构。内容涵盖项目结构设计、各层实现细节及关键技术点,助力开发者掌握DDD在复杂业务系统中的应用。
1937 0
|
12月前
|
Web App开发 Linux Shell
CuteHTTPFileServer下载,局域网文件传输工具下载,chfs支持的最低SSL版本为SSLv3
FinalShell是一款支持多平台的SSH客户端工具,提供一体化服务器管理功能,支持shell与sftp同屏显示、命令自动提示和访问加速,操作简单高效。
1008 12
|
消息中间件 供应链 测试技术
图解 DDD,这一篇总结太全面了!
DDD领取驱动是非常热的架构设计,微服务也有大量涉及,本文详细解析领域驱动设计(DDD),涵盖DDD原理、实践步骤及核心概念等,帮助更好地管理复杂业务逻辑。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
图解 DDD,这一篇总结太全面了!
|
网络协议 Java
在SpringBoot项目中使用Netty实现远程调用
本文介绍了使用Netty解决网络连接性能问题的方法,重点讲解了Netty的NIO特性及其在SpringBoot中的应用。Netty作为高效的NIO框架,支持非阻塞IO,能通过单线程管理多个客户端连接,简化TCP/UDP套接字服务器开发。文章详细展示了Netty在SpringBoot中实现远程调用的过程,包括服务端与客户端代码实现、依赖配置及测试验证。通过示例代码,如`NettyServer`、`NettyClientUtil`等,清晰说明了Netty的工作原理和实际应用,解决了半包等问题,并提供了完整的测试结果。
1037 3
|
存储 监控 druid
Druid、ClickHouse、Doris、StarRocks 的区别与分析
本文对比了 Druid、ClickHouse、Doris 和 StarRocks 四款大数据分析引擎。它们均为 OLAP 引擎,采用列式存储和分布式架构,适用于海量数据分析。Druid 擅长实时分析与高并发查询;ClickHouse 以超高性能著称,适合复杂查询;Doris 提供易用的 SQL 接口,性能均衡;StarRocks 则以其极速查询和实时更新能力脱颖而出。各引擎在数据模型、查询性能、数据更新和存储方面存在差异,适用于不同的业务场景。选择时需根据具体需求综合考虑。
8089 20
|
数据采集 缓存 IDE
Go中遇到http code 206和302的获取数据的解决方案
文章提供了解决Go语言中处理HTTP状态码206(部分内容)和302(重定向)的方案,包括如何获取部分数据和真实请求地址的方法,以便程序员能快速完成工作,享受七夕时光。
1589 0
Go中遇到http code 206和302的获取数据的解决方案