之前的文章介绍了ddd在战术层面的要素,包括entity,value object,aggregate和一些设计模式如repository。在ddd中,repository几乎成为了等同于entity一样的基本要素。
关于aggregate与repository的回顾
aggregate是entity和value object的聚合,它定义了一个边界,在此边界中,数据必须保证数据完整性。
aggregate有一个根root entity,从这个root entity可以获取aggregate内部的其他entity和value object
如图所示,entity 1是aggregate的root entity。
repository是存放和获取aggregate的地方。一种aggregate对应一种repository。
如图,Car与Bicycle都是aggregate,它们各自对应CarRepository与BicycleRepository。
然后Car有4个轮子,所以Car这个aggregate必须保证它有4个轮子的数据完整性。
把这些都关联起来,我们可以话成这样的图
aggregate之间的引用
aggregate之间是通过entity的ID来引用的。Car这个entity,有一个CarId的value object作为Car的识别符。
现在我们想象要做一个购物平台,其中处理订单是我们的一个业务。那我们自然而然会想到需要一个表示订单的domain object。那我们就创建一个Order的entity。Order通过CarId来引用Car这个aggregate
如果还有关于运输的需求。我们为此创建一个叫Delivery的domain object。(当然这个例子有点搞大了,很难想象一般消费者能像买纸巾一样买车子…)
aggregate的缺陷
如果按照ddd提倡的建模方式,我们会比较自然地得出上面的模型。当然Aggregate的范围是可以有讨论余地的。比如把所有entity都扔进一个aggregate中。这方面的讨论可以参考下面的文章。
aggregate的设计策略
我们现在以上面的模型为前提来说说我们可能会遇到的问题。
如果我们需要实现一个订单列表的功能。
简而言之,我们需要获取Delivery,Order和Car的信息。
下面是代码
public List<OrderDTO> viewDeliveryList(UserId userId){
List<Delivery> deliveries=deliveryRepository.find(new DeliverySpecByUserId(userId));
List<OrderId> orderIds=deliveries.toStream().map(delivery->delivery.getOrderId()).collect(Collectors.toList());
List<Order> orders=orderRepository.find(