news 2026/3/22 3:13:23

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/3/12 20:51:33

麦角甾醇PEG生物素;Ergosterol-PEG-Biotin的核心价值

试剂基本信息 英文名称&#xff1a;Ergosterol-PEG-Biotin&#xff1b;Ergosterol 中文名称&#xff1a; 麦角甾醇PEG生物素&#xff1b;甲基胆固醇&#xff1b;麦角固醇 纯度&#xff1a;>95% 外观性状&#xff1a;固体 溶解条件&#xff1a;溶于部分有机溶液 供应厂…

作者头像 李华
网站建设 2026/3/13 2:32:53

Java计算机毕设之基于微信小程序的学生成绩管理系统基于小程序的高校班级管理系统设计与实现(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/3/22 1:52:03

【课程设计/毕业设计】基于微信小程序的企业考勤系统设计与实现基于小程序的企业打卡考勤系统设计与实现【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/3/22 1:03:22

数据库慢如蜗牛?这 5 个 MySQL 优化技巧让查询快 10 倍!

数据库慢如蜗牛?这5个MySQL优化技巧让查询快10倍! 你是否遇到过这样的情况:程序运行越来越慢,用户抱怨页面加载卡顿,而你却不知道问题出在哪里?别担心,今天我们就来解决这个困扰无数开发者的难题! 😱 一个真实的性能灾难故事 小李是一名刚入职的程序员,他负责维护公…

作者头像 李华