乐趣区

关于ddd:关于聚合根领域事件的那点事深入浅出理解DDD-京东云技术团队

作者:京东物流 赵勇萍

前言

最近有空会跟共事探讨 DDD 架构的实际落地的状况,但真实情况是,理论中对于畛域驱动设计中的实体,值对象,聚合根,畛域事件这些战术类的实际落地,每个人了解仍然因人而异,大概率是因为这些概念还是有一些形象,同时有有别于传统的 MVC 架构开发。

在此,通过小 demo 的形式跟大家分享一下我对 DDD 中战术层级的了解,算是抛砖引玉,该了解仅代表我集体在现阶段的一个了解,也可能将来随着业务教训深刻,还会有不同的了解。

既然说是小 demo,还是要从业务场景登程,也就是我最熟知的电商业务场景说起。然而该篇文章里,我会简化一些理论业务场景中的复杂度,通过最小颗粒度的 demo,来反映实际过程中的根本问题。

一个简略的 demo 业务场景

话不多说,我先抛出我本人假如的一个业务场景,就是咱们熟知的电商网站下单购物的场景。具体细节如下:

1. 实体:

• 商品:领有惟一标识、名称、价格、库存等属性。

• 订单:领有惟一标识、下单工夫、状态等属性。订单蕴含多个订单项。

2. 值对象:

• 地址:领有省、市、区、具体地址等属性。

3. 畛域事件:

• 订单创立事件:当用户下单时触发该事件,蕴含订单信息、商品信息等数据。

• 订单领取事件:当用户实现领取时触发该事件,蕴含订单信息、领取金额等数据。

• 订单发货事件:当商家发货时触发该事件,蕴含订单信息、快递公司、快递单号等数据。

4. 聚合根:

• 商品聚合根:蕴含商品实体和相干的值对象,负责商品的创立、批改、查问等操作。

• 订单聚合根:蕴含订单实体和相干的值对象,负责订单的创立、批改、查问等操作。

5. 对外接口服务:

• 创立订单接口:用户提交购买申请后,零碎创立相应的订单,并触发订单创立事件。

• 领取订单接口:用户实现领取后,零碎更新订单状态,并触发订单领取事件。

• 发货接口:商家发货后,零碎更新订单状态,并触发订单发货事件。

• 查问订单接口:用户能够依据订单号等条件查问本人的订单信息。

该 demo 中,商品和订单是两个外围畛域概念,别离由对应的聚合根负责管理。同时,通过定义畛域事件,实现了不同业务场景下的数据更新和告诉。最初,对外提供了一组简略的接口服务,不便零碎的应用和扩大。

demo 的 java 代码实现

好了,有了以上咱们对业务场景的充沛分析,确定了子域,接下来咱们该写咱们的代码。

  1. 商品实体类:
// 省略 getter/setter 办法
public class Product {
    private Long id;
    private String name;
    private BigDecimal price;
    private Integer stock;
}

2. 订单实体类

// 省略 getter/setter 办法
public class Order {
    private Long id;
    private LocalDateTime createTime;
    private Integer status;
    private List orderItems;
}

3. 订单项实体类

// 省略 getter/setter 办法
public class OrderItem {
    private Long id;
    private Product product;
    private Integer quantity;
    private BigDecimal price;
}

4. 地址值对象

// 省略 getter/setter 办法 
public class Address {
    private String province;
    private String city;
    private String district;
    private String detail;
}

5. 畛域事件类

// 订单创立畛域事件
public class OrderCreatedEvent {
    private Order order;
    private List orderItems;

    public OrderCreatedEvent(Order order, List orderItems) {
        this.order = order;
        this.orderItems = orderItems;
    }
}


// 订单领取畛域事件
public class OrderPaidEvent {
    private Order order;
    private BigDecimal amount;

    public OrderPaidEvent(Order order, BigDecimal amount) {
        this.order = order;
        this.amount = amount;
    }
}

// 订单
public class OrderShippedEvent {
    private Order order;
    private String expressCompany;
    private String expressNo;

    public OrderShippedEvent(Order order, String expressCompany, String expressNo) {
        this.order = order;
        this.expressCompany = expressCompany;
        this.expressNo = expressNo;
    }
}

6. 商品聚合根

public class ProductAggregate {
    private ProductService productService;

    public void createProduct(Product product) {productService.create(product);
    }

    public void updateProduct(Product product) {productService.update(product);
    }

    public void deleteProduct(Long productId) {productService.delete(productId);
    }

    public Product getProductById(Long productId) {return productService.getById(productId);
    }
}

7. 订单聚合根

public class OrderAggregate {
    private OrderService orderService;

    public void createOrder(Order order, List orderItems) {orderService.create(order);
        // 触发订单创立事件 
        DomainEventPublisher.publish(new OrderCreatedEvent(order, orderItems));
    }

    public void payOrder(Long orderId, BigDecimal amount) {orderService.pay(orderId, amount);
        // 触发订单领取事件
        DomainEventPublisher.publish(new OrderPaidEvent(orderService.getById(orderId), amount));
    }

    public void shipOrder(Long orderId, String expressCompany, String expressNo) {orderService.ship(orderId, expressCompany, expressNo);
        // 触发订单发货事件 
        DomainEventPublisher.publish(new OrderShippedEvent(orderService.getById(orderId), expressCompany, expressNo));
    }

    public Order getOrderById(Long orderId) {return orderService.getById(orderId);
    }
}

总结

通过以上 demo,对于实体和值对象,大家会很好了解,并且很直观。然而,我额定想重点解释一下聚合根和畛域事件的概念

1. 聚合根

从下面的 demo 能够看出,在合根类中,咱们定义了商品和订单的增、删、查等操作,并且为订单定义了创立订单、领取订单、发货等业务逻辑代码。

聚合根是一个对象,它代表一组相关联的对象的整体。在聚合根外部,能够蕴含多个实体对象和值对象。聚合根通常能够通过惟一标识符来进行辨认和拜访。它是整个聚合的管理者,负责保护聚合之内的一致性,并协调各个实体对象之间的关系。聚合根通常具备丰盛的行为和操作,能够对聚合外部的对象进行简单的操作。

所以说,真正的聚合根内的办法是基于充血模型封装的,而不是仅仅是对对象的数据封装。在聚合根中,对象不仅封装了数据,还蕴含了相应的行为和业务逻辑。这意味着在一个聚合根中,对象能够本人解决本人的业务逻辑,而不须要内部的管制。就如同 demo 中所写的那样,订单对象可能蕴含一些对于订单解决和交付的办法,如确认订单、勾销订单、发货等。

2. 畛域事件

畛域事件是 DDD 中最重要的概念之一,他是解决子域之间耦合的重要伎俩,因为它们提供了一种将畛域概念和业务语言转化为代码的办法。当一个畛域事件产生时,它会触发一些操作,这些操作可能会更改零碎的状态,也可能会导致其余畛域事件的产生。通过对畛域事件进行建模,咱们能够更好地理解业务过程并设计出更加符合实际需要的零碎。

在 DDD 中,畛域事件通常由三个局部组成:

  1. 事件名称:这个名称应该可能简洁明了地形容事件所代表的业务意义。
  2. 相干数据:这些数据蕴含了事件产生时与事件相干的所有信息。例如,在一个电子商务系统中,如果订单被提交,则订单信息以及买家和卖家的信息都应该包含在该事件中。
  3. 发送者和接收者:发送者通常是触发事件的对象,接收者则是事件处理的对象。

畛域事件在 DDD 中有很多用处。例如,它们能够用来触发其余业务流程、更新数据库或告诉其余子系统。它们还能够用于解决一些简单的业务逻辑问题,例如并发、数据同步和错误处理等等。

总之,畛域事件是 DDD 架构中十分重要的概念,它能够帮忙咱们更好地了解业务过程,设计出更加符合实际需要的零碎,并进步零碎的可维护性和可扩展性。

退出移动版