在开发简单的业务逻辑时,可编写面向过程的代码,使用事务脚本模式,即一组类实现行为,另一组类负责存储状态。事务脚本通常是没有状态的类,它访问没有行为的数据类以完成持久化任务。
将业务逻辑组织为领域模型。大多数的业务逻辑由具有状态和行为的类组成,即面向对象的设计。
好处:易于理解、维护、测试和扩展。
它是对面向对象设计的改进。子域和相关联的限界上下文的相关概念是两种战略性的DDD模式。
战术型的模式:实体(entity)、值对象(value object)、工厂(factory)、存储库(repository)、服务(service)、聚合
传统的领域模型是一个由相互关联的类构成的网络,没有明确指定业务对象的边界。如没有指定哪些类是Order业务对象的一部分。
1、概念模糊
2、缺少明确的边界会在更新业务对象时导致问题,如违反最低订单金额不变量约束等业务规则。
聚合是一个边界内的领域对象的集群,如Order聚合由Order实体、多个OrderLineItem、Address等值对象组成。它阐明了更新、删除等操作的范围。
聚合代表了一致的边界
更新整个聚合而不是聚合的一部分,在聚合根上调用更新操作,这会强制执行各种不变量约束。如客户端必须在Order聚合的根上调用方法,而不是只更新订单项的数量,这会强制执行包括最小订单金额内的各种不变量约束。
在领域驱动设计中,设计领域模型的关键部分是识别聚合,以及它们的边界和根
一、只引用聚合根
要求聚合根是聚合中唯一可以由外部类引用的部分。客户端只能通过调用聚合根上的方法来更新聚合。
二、聚合间的引用必须使用主键
如Order使用consumerId引用其Consumer。
好处:
三、在一个事务中,只能创建或更新一个聚合
在微服务架构下,可以确保单个事务的范围不超越服务的边界,它还满足大多数NoSQL数据库的受限事务模型。
每个聚合的更新都是序列化的,更细粒度的聚合将提高应用能够同时处理的请求数量,改善用户体验。而聚合是事务的范围,有时可能需要定义更大的聚合以使特定的聚合更新操作满足事务的原子性,但这降低了可扩展性,也是服务分解的障碍。
典型微服务中,大部分业务逻辑由聚合组成,其余的业务逻辑存在于领域服务和Saga中。
领域事件是聚合发生的事情。由领域模型中的一个类表示。事件通常代表状态的变化。
因为应用程序的其他协作方通常有兴趣了解聚合的状态更改。
领域事件往往以动词的过去分词命名(OrderCreated),还具有元数据(如事件ID和时间戳)
事件接收方可能需要更详细的信息,一种选择是接收方查询聚合服务,但这会产生请求开销。另一种选择是事件增强,即事件包含这部分信息。但接收方需求变化时,事件类都可能需要更改,不过很多情况下,事件需要哪些属性是相对明显的。
通常,需求中描述发送通知的场景中,包含一个领域事件。
还有一种方法是事件风暴,它是快速创建领域模型的有效技术。
将领域专家聚集在一起,准备各色便笺和大白板,准备讨论。
事件风暴的结果是一个以事件为中心的领域模型,由聚合和事件组成,便笺是沿着时间线排列的事件;命令代表用户动作;聚合负责响应命令发出的事件。
使用领域事件进行通信是异步消息传递的一种形式。
聚合直接调用消息传递API,需要将后者作为方法参数传递,这将把基础设施和业务逻辑交织在一起。
另一种方式是服务使用依赖注入来获取对消息传递API的引用,发布事件,当状态发生变化,聚合就会生成事件并将它们返回给服务。
如何可靠地发布领域事件
服务必须使用事务性消息来发布事件,以确保领域事件是作为更新数据库中聚合的事务的一部分对外发布。
领域事件的接收方可以直接使用事件代理的客户端API,但使用更高级的API比较方便,如Eventuate Tram框架的DomainEventDispatcher。
同:
都由诸如服务、JPA支持的实体和存储库等这样的类组成。
不同:
领域模型被组织为DDD聚合,在其上可施加各种约束。与传统对象模型不同,不同聚合的类之间的引用是基于主键而不是对象引用,事务创建或更新单个聚合。聚合在状态变化时会发布领域事件。服务通常使用Saga来维护多个服务之间的数据一致性。