Su的技术博客

  • 首页
  • 原创
  • 视频
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
    • AI工具集
    • 工具清单
    • JSON在线格式化
    • JSON在线比较
    • SQL在线格式化
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. DDD
  3. 正文
                           

【京东】关于聚合根、领域事件的那点事——深入浅出理解DDD

2023-11-26 2018点热度 0人点赞 0条评论
关于聚合根、领域事件的那点事——深入浅出理解DDD
Tech

导读

领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,旨在帮助开发人员更好地理解和解决复杂领域的问题。在DDD中,聚合根和领域事件是两个核心概念,它们在设计和实现领域模型时起到了重要的作用。本文将通过简单的举例方式,深入浅出地介绍聚合根和领域事件,帮助读者更好地理解DDD的核心思想和实践方法。希望本文能够为读者提供有价值的知识和启发,帮助大家在软件开发中更好地应用DDD的思想和方法。

01 
前言
在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!

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

在此,通过小demo的方式跟大家分享一下对DDD中战术层级的理解,算是抛砖引玉,该理解仅代表个人在现阶段的一个理解,也可能未来随着业务经验深入,还会有不同的理解。

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

  

一个简单的demo业务场景

  

理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
话不多说,先抛出假设的一个业务场景,就是熟知的电商网站下单购物的场景。具体细节如下:
2.1  实体
    
  • 商品:拥有唯一标识、名称、价格、库存等属性。
  • 订单:拥有唯一标识、下单时间、状态等属性。订单包含多个订单项。
2.2  值对象
    
  • 地址:拥有省、市、区、详细地址等属性。

2.3  领域事件
    
  • 订单创建事件:当用户下单时触发该事件,包含订单信息、商品信息等数据。
  • 订单支付事件:当用户完成支付时触发该事件,包含订单信息、支付金额等数据。
  • 订单发货事件:当商家发货时触发该事件,包含订单信息、快递公司、快递单号等数据。
2.4  聚合根
    
  • 商品聚合根:包含商品实体和相关的值对象,负责商品的创建、修改、查询等操作。
  • 订单聚合根:包含订单实体和相关的值对象,负责订单的创建、修改、查询等操作。
2.5  对外接口服务
    
  • 创建订单接口:用户提交购买请求后,系统创建相应的订单,并触发订单创建事件。
  • 支付订单接口:用户完成支付后,系统更新订单状态,并触发订单支付事件。
  • 发货接口:商家发货后,系统更新订单状态,并触发订单发货事件。
  • 查询订单接口:用户可以根据订单号等条件查询自己的订单信息。

该demo中,商品和订单是两个核心领域概念,分别由对应的聚合根负责管理。同时,通过定义领域事件,实现了不同业务场景下的数据更新和通知。最后,对外提供了一组简单的接口服务,方便系统的使用和扩展。

03 

  

demo的java代码实现

  

理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。

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

3.1  商品实体类

         
// 省略getter/setter方法
public class Product {
    private Long id;
    private String name;
    private BigDecimal price;
    private Integer stock;
}

 

3.2  订单实体类
    
// 省略getter/setter方法
public class Order {
    private Long id;
    private LocalDateTime createTime;
    private Integer status;
    private List orderItems;
}

 

3.3  订单项实体类
    
// 省略getter/setter方法
public class OrderItem {
    private Long id;
    private Product product;
    private Integer quantity;
    private BigDecimal price;
}

 

3.4  地址值对象
    
// 省略getter/setter方法 
public class Address {
    private String province;
    private String city;
    private String district;
    private String detail;
}

 

3.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;
    }
}

 

3.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);
    }
}

 

3.7  订单聚合根
    
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);
    }
}

 

04 

  总结  

理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目

通过以上demo,对于实体和值对象,大家会很好理解,并且很直观。但是,额外想重点解释一下聚合根和领域事件的概念。

‍

4.1  聚合根
    

从上面的demo可以看出,在合根类中,定义了商品和订单的增、删、查等操作,并且为订单定义了创建订单、支付订单、发货等业务逻辑代码。

聚合根是一个对象,它代表一组相关联的对象的整体。在聚合根内部,可以包含多个实体对象和值对象。聚合根通常可以通过唯一标识符来进行识别和访问。它是整个聚合的管理者,负责维护聚合之内的一致性,并协调各个实体对象之间的关系。聚合根通常具有丰富的行为和操作,可以对聚合内部的对象进行复杂的操作。

所以说,真正的聚合根内的方法是基于充血模型封装的,而不是仅仅是对对象的数据封装。在聚合根中,对象不仅封装了数据,还包含了相应的行为和业务逻辑。这意味着在一个聚合根中,对象可以自己处理自己的业务逻辑,而不需要外部的控制。就如同demo中所写的那样,订单对象可能包含一些关于订单处理和交付的方法,如确认订单、取消订单、发货等。

4.2  领域事件
    

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

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

  1. 事件名称:这个名称应该能够简洁明了地描述事件所代表的业务意义。

  2. 相关数据:这些数据包含了事件发生时与事件相关的所有信息。例如,在一个电子商务系统中,如果订单被提交,则订单信息以及买家和卖家的信息都应该包括在该事件中。

  3. 发送者和接收者:发送者通常是触发事件的对象,接收者则是事件处理的对象。

领域事件在DDD中有很多用途。例如,它们可以用来触发其他业务流程、更新数据库或通知其他子系统。它们还可以用于解决一些复杂的业务逻辑问题,例如并发、数据同步和错误处理等等。

总之,领域事件是DDD架构中非常重要的概念,它可以帮助更好地理解业务过程,设计出更加符合实际需求的系统,并提高系统的可维护性和可扩展性。

‍

打造SAAS化服务的会员徽章体系,可以作为标准的产品化方案统一对外输出。结合现有平台的通用能力,实现会员行为全路径覆盖,并能结合企业自身业务特点,规划相应的会员精准营销活动,提升会员忠诚度和业务的持续增长。
▪
底层能力:维护用户基础数据、行为数据建模、用户画像分析、精准营销策略的制定

▪功能支撑:会员成长体系、等级计算策略、权益体系、营销底层能力支持

▪用户活跃:会员关怀、用户触达、活跃活动、业务线交叉获客、拉新促活

‍

‍

本文仅供学习!所有权归属原作者。侵删!文章来源: 京东技术 -京东物流 赵勇萍 :http://mp.weixin.qq.com/s/KL_MNsssapVLVP7kR-yA1w

更多文章:

  1. 系统设计 | 高精度计算
  2. 用这10个技巧帮你写出更好的Java代码
  3. 殷浩详解DDD系列 第一讲 - Domain Primitive
  4. 解构领域驱动设计(三):领域驱动设计
  5. 浅谈DDD中的聚合
  6. 殷浩详解DDD系列 第二讲 - 应用架构
  7. 设计模式在外卖营销业务中的实践
  8. 殷浩详解DDD 第四讲:领域层设计规范
  9. 殷浩详解DDD 第三讲 - Repository模式
  10. 解构领域驱动设计(二):分层架构
标签: 京东 转载 ddd 领域驱动设计 聚合根 领域事件
最后更新:2023-11-26

coder

分享干货文章,学习先进经验。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

广告
文章目录
  • 导读
  • 一个简单的demo业务场景
  • demo的java代码实现
最新 热点 推荐
最新 热点 推荐
干货 | 论Elasticsearch数据建模的重要性 马蜂窝消息总线——面向业务的消息服务设计 基于 MySQL Binlog 实现可配置的异构数据同步 视频笔记:Google发布Agent2Agent协议 视频笔记:什么是微服务,为什么是微服务? 视频笔记:什么是AI 智能体? 视频笔记:什么是Flink? 如何秒级实现接口间“幂等”补偿:一款轻量级仿幂等数据校正处理辅助工具
Elasticsearch 使用误区之六——富文本内容写入前不清洗基于 MySQL Binlog 实现可配置的异构数据同步马蜂窝消息总线——面向业务的消息服务设计干货 | 论Elasticsearch数据建模的重要性你可以不用RxJava,但必须得领悟它的思想!如何秒级实现接口间“幂等”补偿:一款轻量级仿幂等数据校正处理辅助工具视频笔记:什么是Flink?视频笔记:什么是AI 智能体?
Eureka源码剖析之六:自我保护机制 AI辅助编码,应该怎么选? Elasticsearch 使用误区之一——将 Elasticsearch 视为关系数据库! JVM和机器规格调优在有赞的实践 ChatGLM:ChatGPT的替代方案 Eureka源码剖析之四:服务续约 京东平台研发朱志国:领域驱动设计(DDD)理论启示 基于DDD的微服务设计和开发实战

CRUD (1) Event Sourcing (1) graphql (1) id (1) NoSQL (1) quarkus (1) rest (1) RocketMQ (2) Spring Boot (1) zk (1) zookeeper (1) 上下文 (1) 事务消息 (1) 二级缓存 (1) 值对象 (1) 关系数据库 (1) 分布式缓存 (1) 原子性 (1) 唯一ID (1) 商品 (1) 多对多 (1) 子域 (1) 字符集 (1) 客户端心跳 (1) 幂等 (2) 干货 (1) 并发 (1) 应用场景 (1) 应用架构图 (1) 康威定律 (2) 异步复制 (1) 微服务架构 (2) 总体方案 (1) 技术方案 (2) 技术架构 (2) 技术架构图 (1) 技能 (1) 持续集成 (1) 支撑域 (1) 故障恢复 (1) 数据架构图 (1) 方案选型 (1) 日记 (1) 服务发现 (1) 服务治理 (1) 服务注册 (2) 机房 (1) 核心域 (1) 泄漏 (1) 洋葱架构 (1) 消息队列 (5) 源码剖析 (1) 灰度发布 (1) 熔断 (1) 生态 (1) 画图工具 (1) 研发团队 (1) 线程 (2) 组织架构 (1) 缓存架构 (1) 编码 (1) 视频 (18) 读写分离 (1) 贵州 (1) 软件设计 (1) 迁移 (1) 通用域 (1) 集群化 (1) 雪花算法 (1) 顺序消息 (1)

推荐链接🔗
  • AI工具集
  • 工具箱🛠️

COPYRIGHT © 2014-2025 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2

x