领域驱动设计5
聚合根:一组相关对象的集合。作为一整体被外界访问。聚合根就是这个聚合的根节点
聚合是一个非常重要的概念。核心领域往往都需要用聚合来表达。其次,聚合在技术上有较高的价值。可以指导详细设计。
聚合由根实体。值对象和实体组成。
好的聚合根:
- 边界内的内容具有一致性:在一个事务中只修改一个聚合实例。如果发现边界内很难接受强一致。不管是出于性能或产品需求的考虑。应该考虑剥离出独立的聚合。采用base。
- 设计小聚合:大部分的聚合都可以只包含根实体。而无需包含其他实体。即使一定要包含,可以考虑将其创建为值对象。
- 通过唯一标识来引其他聚合或实体:当存在对象之间的关联时。建议引用其唯一表示而非引用其整体对象。如果是外部上下文中的实体,引用其唯一标识或将需要的属性构造值对象。如果构造复杂。建议使用工厂方法包装来屏蔽掉创建逻辑。
聚合内部多个组成对象的关系可以用来指导数据库创建。但不可避免存在一定的抗阻。如果聚合中存在List,那么在数据库中建立1:N的关联需要将值对象单独建表,此时是有id的。建议不要把id暴露。
领域服务:一些重要的领域行为 可以归类为领域服务。既不是实体也不是值对象范畴
当采用微服务架构的风格。一切领域逻辑的对外暴露都需要通过领域服务来进行。如原本由聚合根暴露的业务逻辑也要依托于领域服务。
领域事件: 领域事件是对领域内发生的活动进行的建模。
抽奖平台的核心上下文是抽奖上下文。对抽奖上下文建模。
在抽奖上下文中 通过抽奖聚合根来控制抽奖行为。可以看到,一个抽奖包括抽奖ID(LotteryId) 以及多个奖池(AwardPool).而一个奖池针对一个特定的用户群体设置了多个奖品。
另外在抽奖领域中 我们还会使用抽奖结果作为输出信息。使用用户领奖记录作为存根。
DDD工程实现
import com.example.lottery.*; //抽奖上下文
import com.example.riskcontrol.* ;//风控上下文
import com.example.counter.* ;//计数上下文
import com.example.condition.* ;//活动准入上下文
import com.example.sock.*;//库存上下
领域对象
DDD要解决的一个重要问题。就是解决对象的贫血问题。这里我们用之前定义的抽奖聚合根和奖池值对