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

相关文章
|
Java
《Java并发库系列三》一newSingleThreadScheduledExecutor
newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,如果任务多于一个,任务将按先后顺序执行。
1428 0
|
Arthas SQL Java
Arthas之WatchSql
在使用Arthas排查线上问题的时候,有些时候我们需要查看某些Sql的生成,如果线上没有完备的APM的话,那么如何临时查看呢,前几篇文章我们分析了Mybatis的插件机制,如果你还记得的话,我们可以通过watch这个插件进行查看。
3095 1
Arthas之WatchSql
|
11月前
|
负载均衡 网络协议 算法
一文读懂什么是Nginx?它能否实现IM的负载均衡?
Nginx(及其衍生产品)是目前被大量使用的服务端反向代理和负载均衡方案,从某种意义上来讲,Nginx几乎是低成本、高负载Web服务端代名词。 如此深入人心的Nginx,很多人也想当然的认为,在IM或消息推送等场景下是否也能使用Nginx来解决负载均衡问题? 另外,即时通讯网的论坛和QQ群里也经常有人问起,Nginx是否能支持TCP、UDP、WebSocket的负载
302 4
|
8月前
|
人工智能 前端开发 JavaScript
SpringBoot实现网页消息推送的5种方法
本文详细介绍了在SpringBoot中实现网页消息推送的几种主流方案,包括短轮询、长轮询、SSE(Server-Sent Events)、WebSocket以及STOMP。每种方案各有优缺点,适用于不同的场景需求。短轮询简单易实现但效率低;长轮询提升了实时性但仍有限制;SSE适合单向通信且轻量高效;WebSocket支持全双工通信,适合高实时性要求的场景;STOMP基于WebSocket,提供更高级的消息传递功能。通过对比分析,开发者可根据业务需求、性能要求及浏览器兼容性选择最适合的技术方案,同时可结合多种技术实现优雅降级,优化用户体验。
1599 57
|
8月前
|
SQL 自然语言处理 关系型数据库
通义灵码2.5来袭!MCP 功能直接让开发效率提升300%(附实战案例)
通义灵码2.5是阿里云推出的AI编码助手,以智能协作为核心,深度融合开发全流程。其三大升级点包括:编程智能体实现任务自主规划、MCP工具生态支持自然语言生成SQL、记忆进化系统个性化适配开发者习惯。通过自然语言即可完成数据库操作、代码生成与优化,大幅提升开发效率。此外,还具备工程级变更管理、多文件协同编辑及版本控制功能,适用于多种IDE环境,为企业提供安全高效的开发解决方案。
|
消息中间件 存储 NoSQL
物联网设备频繁断网,如何打赢智慧社区的流量洪峰之战?
本文详细介绍了智慧社区中物联网(IOT)技术的应用,重点讨论了物联网流量洪峰的处理方法。文章分析了上行和下行消息的特点,并提出了上下行拆分、多泳道消息队列、实时消息优先处理、连接计算存储分离及推拉结合的消息策略,以优化消息队列,确保系统稳定运行。通过这些技术手段,智慧社区的物联网设备能在各种场景中保持高效运作。
253 2
|
存储 设计模式 数据可视化
DDD新手入门:领域模型设计的七个核心概念
小米,29岁程序员,分享领域模型落地知识。文章解析领域、子域、限界上下文、领域对象、聚合、工厂与仓库等概念,助你理解领域驱动设计。
817 1
|
负载均衡 算法 应用服务中间件
5大负载均衡算法及原理,图解易懂!
本文详细介绍负载均衡的5大核心算法:轮询、加权轮询、随机、最少连接和源地址散列,帮助你深入理解分布式架构中的关键技术。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
5大负载均衡算法及原理,图解易懂!