news 2026/2/28 6:19:48

DDD领域驱动设计之实战指南:从理论到落地的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DDD领域驱动设计之实战指南:从理论到落地的完整实践

基于SmartRM智能零售机项目的Trade(交易)模块实战解析

目录

  1. DDD四层架构概述
  2. 领域层(Domain Layer)详解
  3. 应用层(Application Layer)详解
  4. 适配器层(Adapter Layer)详解
  5. 基础设施层(Infrastructure Layer)详解
  6. 依赖关系与边界划分
  7. DDD核心概念落地实践
  8. 最佳实践与反模式

一、DDD四层架构概述

1.1 架构分层原则

DDD采用经典的四层架构,从上到下依次为:

┌─────────────────────────────────────────┐ │ Adapter Layer (适配器层) │ │ - API Controllers │ │ - Event Handlers │ │ - Repository Implementations │ │ - Remote Service Implementations │ ├─────────────────────────────────────────┤ │ Application Layer (应用层) │ │ - Application Services │ │ - DTOs │ │ - Executors │ ├─────────────────────────────────────────┤ │ Domain Layer (领域层) │ │ - Entities / Aggregates │ │ - Value Objects │ │ - Domain Events │ │ - Domain Services │ │ - Repository Interfaces │ │ - Remote Service Interfaces │ ├─────────────────────────────────────────┤ │ Infrastructure Layer (基础设施层) │ │ - Data Objects (DO) │ │ - Mappers │ │ - Error Codes │ └─────────────────────────────────────────┘

1.2 目录结构标准

以Trade模块为例,标准的DDD项目结构如下:

trade/ ├── adapter/ # 适配器层 │ ├── api/ │ │ └── controller/ # REST API控制器 │ ├── eventhandler/ # 领域事件处理器 │ ├── remote/ # 远程服务实现(防腐层) │ └── repository/ │ └── impl/ # 仓储接口实现 ├── application/ # 应用层 │ ├── dto/ # 数据传输对象 │ ├── executor/ # 任务执行器 │ └── AppTradeService.java # 应用服务 ├── domain/ # 领域层(核心) │ ├── event/ # 领域事件 │ ├── remote/ # 远程服务接口定义 │ ├── repository/ # 仓储接口定义 │ ├── Order.java # 实体 │ ├── SlotVendingMachine.java # 聚合根 │ ├── StockedCommodity.java # 值对象 │ ├── OrderState.java # 枚举 │ └── ActivityService.java # 领域服务 └── infrastructure/ # 基础设施层 ├── dataobject/ # 数据对象(DO) ├── mapper/ # MyBatis Mapper └── TradeError.java # 错误码定义

二、领域层(Domain Layer)详解

领域层是DDD的核心,包含业务逻辑和规则,独立于技术实现。

2.1 聚合根(Aggregate Root)

定义位置:domain/XXXAggregate.java

职责:

  • 作为聚合的入口点,保证聚合内的一致性边界
  • 封装业务规则和状态转换逻辑
  • 发布领域事件
  • 管理聚合内的生命周期

实战示例:trade/domain/SlotVendingMachine.java:29-218

/** * 货道售卖机聚合根 * 继承AggregateBase获得版本号、事件总线等基础能力 */publicclassSlotVendingMachineextendsAggregateBase{// 聚合状态privatelongmachineId;privateSlotVendingMachineStatestate;privateOrdercurOrder;// 聚合内实体/** * 核心业务方法:选择商品 * 1. 校验设备状态 * 2. 校验库存 * 3. 生成订单 * 4. 发布领域事件 * 5. 调用支付服务 * 6. 更新状态 */publicPaymentQrCodeselectCommodity(Collection<StockedCommodity>commodities,TradeDeviceServicedeviceService,TradePayServicepayService,PlatformTypeplatformType){// 业务规则校验if(state!=SlotVendingMachineState.Ready){thrownewDomainException(TradeError.VendingMachineStateNotRight);}if(!checkInventory(commodities,deviceService)){thrownewDomainException(TradeError.InventoryCheckFail);}// 生成订单curOrder=this.generateOrder(commodities);// 发布领域事件emitEvent(newOrderCreatedEvent(this.machineId,curOrder));// 状态转换state=SlotVendingMachineState.Trading;// 调用外部服务PaymentQrCoderet=payService.startQrCodePayForOrder(platformType,curOrder);curOrder.setPaymentId(ret.getPaymentId());// 增加版本号(乐观锁)incVersion();returnret;}// 使用Builder模式构建聚合publicstaticBuilderBuilder(){returnnewBuilder();}publicstaticclassBuilder{privatelongmachineId;privateSlotVendingMachineStatestate;privateOrdercurOrder;privatelongversion;privateDomainEventBuseventBus;publicSlotVendingMachinebuild(){// 构建时进行必要的校验if(this.eventBus==null){thrownewDomainException(CommonError.UnExpected);}// ... 构建逻辑}}}

关键要点:

  1. ✅ 聚合根继承AggregateBase获得版本控制能力
  2. ✅ 使用Builder模式构建复杂对象
  3. ✅ 业务方法封装完整的业务规则
  4. ✅ 通过emitEvent发布领域事件
  5. ✅ 使用incVersion()支持乐观锁

2.2 实体(Entity)

定义位置:domain/XXXEntity.java

职责:

  • 有唯一标识的领域对象
  • 封装业务行为和状态
  • 可以发布领域事件

实战示例:trade/domain/Order.java:17-162

/** * 订单实体 * 特征:有orderId作为唯一标识 */publicclassOrder{// 唯一标识privatelongorderId;// 属性privatelongmachineId;privatelongpaymentId;privateOrderStatestate;privateOrderTypetype;privateList<StockedCommodity>commodities;// 事件总线(用于发布事件)privateDomainEventBuseventBus;/** * 业务方法:取消订单 * 改变状态 + 发布领域事件 */publicvoidcancel(){state=OrderState.Canceled;eventBus.post(newOrderCanceledEvent(this));}/** * 业务方法:订单成功 */publicvoidsucceed(){state=OrderState.Success;eventBus.post(newOrderSucceededEvent(this));}/** * 业务计算:计算订单总金额 */publicBigDecimaltotalAmount(){BigDecimalret=newBigDecimal(0);for(StockedCommoditycommodity:commodities){ret=ret.add(commodity.getPrice().multiply(newBigDecimal(commodity.getCount())));}returnret;}// 私有构造函数,强制使用BuilderprivateOrder(){}// Builder模式publicstaticclassBuilder{// ... Builder实现publicOrderbuild(){// 构建时进行业务规则校验if(machineId==0||state==null||type==null){thrownewDomainException(CommonError.InvalidProperty);}// ...}}}

实体 vs 聚合根:

  • 相同点: 都有唯一标识,都封装业务逻辑
  • 不同点:
    • 聚合根是对外的统一入口
    • 实体可以被聚合根引用,但不能单独被外部访问

2.3 值对象(Value Object)

定义位置:domain/XXXValueObject.java或直接在domain根目录

职责:

  • 无唯一标识,通过属性值判断相等性
  • 不可变对象(Immutable)
  • 封装概念完整性

实战示例:trade/domain/StockedCommodity.java

/** * 库存商品值对象 * 特征: * 1. 无唯一ID(commodityId是商品ID,不是这个值对象的ID) * 2. 通过全部属性值判断相等性 * 3. 不可变(所有字段final,只有getter无setter) */publicclassStockedCommodity{privatefinalStringcommodityId;privatefinalStringname;privatefinalStringimageUrl;privatefinalBigDecimalprice;privatefinalintcount;// 构造时赋值,之后不可变publicStockedCommodity(StringcommodityId,Stringname,StringimageUrl,BigDecimalprice,intcount){this.commodityId=commodityId;this.name=name;this.imageUrl=imageUrl;this.price=price;this.count=count;}// 只提供getter,无setterpublicStringgetCommodityId(){returncommodityId;}publicStringgetName(){returnname;}publicBigDecimalgetPrice(){returnprice;}publicintgetCount(){returncount;}// 重写equals和hashCode(基于所有属性)@Overridepublicbooleanequals(Objecto){if(this==o)returntrue;if(!(oinstanceofStockedCommodity))returnfalse;StockedCommoditythat=(StockedCommodity)o;returncount==that.count&&Objects.equals(commodityId,that.commodityId)&&Objects.equals(name,that.name)&&Objects.equals(price,that.price);}}

关键原则:

  1. ✅ 所有字段声明为final
  2. ✅ 只提供getter,不提供setter
  3. ✅ 通过构造函数一次性初始化
  4. ✅ 重写equalshashCode

2.4 领域事件(Domain Event)

定义位置:domain/event/XXXEvent.java

职责:

  • 表示领域中发生的重要业务事件
  • 实现聚合间的解耦通信
  • 支持事件溯源

实战示例:trade/domain/event/OrderCreatedEvent.java:12-55

/** * 订单创建事件 * 继承DomainEvent基类 */publicclassOrderCreatedEventextendsDomainEvent{// 事件携带的数据privatelongmachineId;privatelongorderId;privateOrderTypeorderType;privateBigDecimaltotalAmount;/** * 构造函数:从聚合或实体构造事件 */publicOrderCreatedEvent(longmachineId,Orderorder){super("trade.OrderCreatedEvent");// 事件名称this.machineId=machineId;this.orderId=order.getOrderId();this.orderType=order.getType();this.totalAmount=order.totalAmount();}/** * 事件分区键(用于保证同一聚合的事件顺序) */@OverridepublicStringkey(){returnLong.toString(machineId);}// Getters...}

事件命名规范:

  • 使用过去式:OrderCreated,PaymentSucceeded,OrderCanceled
  • 命名格式:{聚合名}{动作过去式}Event

2.5 仓储接口(Repository Interface)

定义位置:domain/repository/XXXRepository.java

职责:

  • 定义聚合的持久化契约
  • 提供聚合的查询和保存方法
  • 隔离领域层与基础设施层

实战示例:trade/domain/repository/OrderRepository.java:9-19

/** * 订单仓储接口 * 定义在领域层,实现在适配器层 */publicinterfaceOrderRepository{/** * 根据ID获取订单聚合 */OrdergetOrderById(longorderId);/** * 添加新订单 */
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/26 8:18:52

社会网络仿真软件:NodeXL_(3).NodeXL安装与基本设置

NodeXL安装与基本设置 在开始使用NodeXL进行社会网络分析之前&#xff0c;首先需要安装NodeXL并进行一些基本设置。本节将详细介绍如何安装NodeXL&#xff0c;并配置其基本环境&#xff0c;以便您能够顺利地进行后续的社会网络仿真和分析工作。 安装NodeXL NodeXL是一个基于…

作者头像 李华
网站建设 2026/2/26 7:25:26

Excel LARGE函数详解:提取前几名数据与排名实战案例

掌握LARGE函数的精髓&#xff0c;轻松处理数据排名与分析&#xff01; 一、LARGE函数基础语法 函数定义 LARGE(array, k) 函数用于返回数据集中第 k 个最大值。 参数说明 array&#xff1a;必需。需要从中选择第 k 个最大值的数组或数据区域 k&#xff1a;必需。返回值在数…

作者头像 李华
网站建设 2026/2/24 13:17:20

MyBatis的分页插件

分页插件使用步骤 1 添加依赖<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version></dependency>2 配置分页插件 在MyBatis的核心配置文件中配置插件<plugi…

作者头像 李华
网站建设 2026/2/24 5:16:48

python景区门票管理微信小程序

目录 景区门票管理微信小程序的摘要 开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 景区门票管理微信小程序的摘要 景区门票管理微信小程序旨在通过数字化手段提升景区门票管理效率&#…

作者头像 李华
网站建设 2026/2/27 10:19:53

python竞赛报名管理的微信小程序_uux

目录 Python竞赛报名管理的微信小程序_uux的摘要 开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; Python竞赛报名管理的微信小程序_uux的摘要 微信小程序_uux是一个基于Python开发的竞赛报…

作者头像 李华