之前的文章介绍了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(

本文探讨了领域驱动设计(DDD)中的CQRS(命令查询责任分离)原则。通过回顾aggregate与repository,指出aggregate设计可能带来的问题,尤其是对于查询效率的影响。CQRS将查询和命令操作分离,分别使用不同的模型处理,以提高系统性能。文章详细阐述了如何实现CQRS,包括Command和Query的处理,并给出了一些实现时的注意事项,如避免在Query Service中涉及业务逻辑。

4032

被折叠的 条评论
为什么被折叠?



