首页/新闻资讯/正文详情

Java DDD(领域驱动设计)

发布时间:2026/9/26 0:53:01 来源:云帆数科 栏目:资讯中心
Java DDD(领域驱动设计)
一句话核心DDD领域驱动设计不是一套框架而是一种代码组织哲学。它要求你用代码直接翻译业务语言而不是把业务逻辑散落在增删改查CRUD里。对于Java开发者最经典的DDD范式就是**“四层架构” “六大战术模式”。为了让你秒懂我们把项目类比为“一家餐厅”**表现层Controller 服务员接收顾客指令。应用层Application 大堂经理调度任务发号施令。领域层Domain 厨师长 菜谱核心资产业务规则所在。基础设施层Infrastructure 冰箱、灶台数据库、Redis、MQ。下面我直接给你展示标准的Java DDD包结构和核心代码范式一看就懂。1. 标准的Java DDD包结构范式骨架com.example.order/ ├── interfaces/ # 表现层处理HTTP/RPC │ └── OrderController.java ├── application/ # 应用层用例编排无业务逻辑 │ ├── service/ # 应用服务如OrderApplicationService │ └── dto/ # 数据传输对象Request/Response ├── domain/ # 领域层核心只依赖Java本身不依赖Spring/DB │ ├── model/ # 领域模型 │ │ ├── aggregate/ # 聚合根如Order │ │ ├── entity/ # 实体如OrderItem │ │ └── vo/ # 值对象如Address, Money │ ├── service/ # 领域服务处理跨多个实体的复杂业务 │ └── repository/ # 仓储接口定义“我需要什么数据”不实现 └── infrastructure/ # 基础设施层实现Domain层的接口 ├── repository/ # 仓储实现JPA/MyBatis └── config/ # 配置类2. 六大战术模式Java代码实战为了便于理解我们模拟一个**“下单”**场景必须验证地址且订单总价要打折。① 值对象 (Value Object) —— 用record或不可变类特点没有唯一ID通过属性值判断相等性。封装业务规则。// 值对象地址publicrecordAddress(Stringprovince,Stringcity,Stringdetail){publicAddress{// 业务规则地址不能为空直接写在构造方法里if(provincenull||citynull){thrownewIllegalArgumentException(省市必填);}}}// 值对象金额publicclassMoney{privatefinalBigDecimalamount;privatefinalStringcurrency;// 通常用枚举// 封装加法逻辑而不是在Service里用BigDecimal算publicMoneyadd(Moneyother){...}}② 实体 (Entity) —— 有唯一ID可变Entity// 注意这里的注解是JPA的但DDD要求Domain层纯POJO所以通常把这个类放在infrastructure层做映射或者在Domain层不加Table注解。publicclassOrderItem{privateLongitemId;// 唯一标识privateStringproductName;privateIntegerquantity;privateMoneyprice;// 引用值对象}③ 聚合根 (Aggregate Root) ——DDD最重要的范式聚合根是外部访问聚合的唯一入口。比如“订单(Order)”和“订单项(OrderItem)”是整体外部只能操作Order不能直接修改OrderItem。// 领域层 - 聚合根publicclassOrder{privateLongorderId;// 唯一标识privateAddressshipAddress;// 值对象privateListOrderItemitems;// 实体集合privateOrderStatusstatus;// 核心业务方法充血模型业务逻辑写在实体内部而不是Service里publicvoidplaceOrder(){// 规则1下单必须校验地址封装在领域内部if(this.shipAddressnull){thrownewBusinessException(缺少收货地址);}// 规则2计算总价并打折满100减10MoneytotalcalculateTotal();if(total.amount().compareTo(newBigDecimal(100))0){// 打折逻辑...}this.statusOrderStatus.PLACED;// 发布领域事件可选DomainEventPublisher.publish(newOrderPlacedEvent(this.orderId));}// 计算总价也不允许Service插手由实体自己算privateMoneycalculateTotal(){returnitems.stream().map(OrderItem::getPrice).reduce(Money::add).orElse(...);}}④ 仓储接口 (Repository) ——依赖倒置的核心Domain层定义“我要什么”Infrastructure层实现“怎么拿”。// domain/repository/OrderRepository.java (接口)publicinterfaceOrderRepository{OrderfindById(Longid);voidsave(Orderorder);// 传入聚合根整个聚合一起保存}// infrastructure/repository/OrderRepositoryImpl.java (实现)RepositorypublicclassOrderRepositoryImplimplementsOrderRepository{AutowiredprivateOrderJpaMappermapper;// MyBatis或JPAOverridepublicvoidsave(Orderorder){// 1. 保存Order主表// 2. 保存OrderItem子表全部替换策略// 领域层不知道底层是MySQL还是Redis}}⑤ 领域服务 (Domain Service)当业务逻辑不属于某个具体的实体时使用比如转账涉及两个账户。// domain/service/TransferService.javapublicclassTransferService{publicvoidtransfer(Accountfrom,Accountto,Moneyamount){from.debit(amount);// 实体自己的方法to.credit(amount);}}⑥ 应用层 (Application Service) ——极薄的一层只做三件事拿数据、调领域方法、存数据。绝对不写 if-else 业务判断。// application/service/OrderAppService.javaServiceTransactionalpublicclassOrderAppService{privatefinalOrderRepositoryorderRepository;// 用例用户下单publicLongplaceOrder(PlaceOrderCommandcmd){// 1. 从仓储拿聚合根如果是新建则newOrderordernewOrder();// 2. 调用领域方法业务逻辑进入领域层order.placeOrder();// 3. 仓储保存orderRepository.save(order);// 4. 返回结果returnorder.getOrderId();}}3. 必须遵守的“铁律”DDD Java范式红线层级是否允许依赖Spring注解是否允许依赖数据库职责领域层 (Domain)❌ 禁止纯Java POJO❌ 禁止只写interface定义规则写业务逻辑方法应用层 (Application)✅ 允许 (Service)❌ 禁止编排用例调用领域方法事务发起点基础设施层 (Infra)✅ 允许 (Repository)✅ 允许实现接口处理SQL、Redis、MQ表现层 (Interfaces)✅ 允许 (RestController)❌ 禁止参数校验、返回JSON为什么领域层禁止用Spring注解因为DDD追求**“业务逻辑与技术解耦”**。如果Autowired进了Domain换用Quarkus或单元测试时就废了。Domain应该是可以脱离Spring直接用new Order().placeOrder()就能跑单元测试的。4. 贫血模型 vs 充血模型一眼辨别真假DDD传统CRUD贫血Order类只有getter/setter所有if/else全在OrderServiceImpl里。→这是假DDD。DDD范式充血Order类拥有placeOrder()、cancel()、calculateTotal()方法。OrderAppService只有寥寥几行调用。→这是真DDD。总结记住这张脑图表现层接收请求 →应用层从基础设施层拿到仓储接口的实现 → 交给领域层的聚合根执行业务方法内部包含实体和值对象的规则 → 应用层再通过仓储存回去。如果只是简单的增删改查请不要用DDD杀鸡用牛刀。但如果业务逻辑极其复杂如电商、金融、医疗这个Java范式就是防止代码腐烂的最强武器。记住核心口诀“让代码说业务的话让数据库滚去基础设施层”。

相关推荐

基于BERT的中文文本情感分类实战指南
基于BERT的中文文本情感分类实战指南

1. 项目概述中文文本情感分类是自然语言处理领域的基础任务之一,其目标是将给定的中文文本划分为积极、消极或中性等情感类别。随着预训练语言模型的兴起,基于BERT的文本分类方法已成为当前主流技术路线。本文将全面解析如何利用BERT预训练模型构建中文情… · 2026/9/26 0:51:30

时序预测模型选型与Matlab实现:Transformer与BiLSTM对比
时序预测模型选型与Matlab实现:Transformer与BiLSTM对比

1. 时序预测模型选型全景图时序预测作为机器学习领域的经典问题,在电力负荷预测、股票价格分析、气象预报等领域有着广泛应用。最近在帮某能源企业做负荷预测系统时,我系统对比了Transformer、BiLSTM等五种主流模型的实测表现。本文将基于Matlab平台&… · 2026/9/17 6:45:57

【OpenHarmony/HarmonyOS】游戏应用生命周期治理:页面、Canvas、定时器、音频与网络如何正确收放
【OpenHarmony/HarmonyOS】游戏应用生命周期治理:页面、Canvas、定时器、音频与网络如何正确收放

【OpenHarmony/HarmonyOS】游戏应用生命周期治理:页面、Canvas、定时器、音频与网络如何正确收放游戏项目常见的“第二次进入变快两倍”“退出后仍耗电”“BGM 重复播放”,本质上都是生命周期没有闭环。本文从 UIAbility 到 ArkUI 组件,整理一… · 2026/9/13 23:43:02

QQ通讯组件做网页在线客服:临时会话原理与接入避坑指南
QQ通讯组件做网页在线客服:临时会话原理与接入避坑指南

先说个很常见的场景:一个访客点开你网站上的“在线客服”,浏览器立刻唤起本机QQ,弹出一个聊天窗口,对方不用加好友、不用下载任何插件,直接就能和你对话。这种体验,其实就是“QQ通讯组件”在网页里的典型应… · 2026/9/26 0:52:57

Django大数据选品实战:直播带货商品评分模型与可视化全解析
Django大数据选品实战:直播带货商品评分模型与可视化全解析

我做直播电商相关系统也有几年了,去年带学生做毕业设计时,选了“基于Django大数据在直播带货商品选品中的应用”这个方向。这个题目乍一看有点“拼盘”:Django是大数据?选品用什么大数据?实际上把一个真实的小型数据决… · 2026/9/26 0:52:32

深入 Agent Sprite Forge 后处理引擎:洋红泛洪、连通域切帧与 GIF 编码原理
深入 Agent Sprite Forge 后处理引擎:洋红泛洪、连通域切帧与 GIF 编码原理

深入 Agent Sprite Forge 后处理引擎:洋红泛洪、连通域切帧与 GIF 编码原理 【免费下载链接】agent-sprite-forge Agent Skill for generating 2D sprite sheets and map, transparent PNG frames, and animated GIFs from prompts. 项目地址: https://gitcode.co… · 2026/9/26 0:52:32

命令行批量下载抖音无水印视频:从单条到主页归档实战
命令行批量下载抖音无水印视频:从单条到主页归档实战

1. 为什么我放弃了图形工具,转回命令行做抖音视频归档做内容运营或者素材收集的朋友,大概率都遇到过这样的场景:刷到一个特别对味的账号,想把ta主页的视频全部存下来做参考,结果一条条点开、复制链接、打开解析网站、等… · 2026/9/26 0:52:26

UE5 GAS框架实战:构建可扩展ARPG战斗系统的核心方法
UE5 GAS框架实战:构建可扩展ARPG战斗系统的核心方法

1. 先别急着写代码:ARPG战斗框架到底在解决什么问题如果你在UE里做过ARPG,一定体会过战斗系统写到后期的那种窒息感。普攻连段、闪避无敌帧、受击硬直、怪物AI、伤害数字、BUFF叠层、技能打断、镜头冲击……表面上每个功能都不难,但一旦它们互… · 2026/9/26 0:52:20

贵州正规的除尘器加工厂哪家靠谱?株洲菲尔特生产厂靠谱商家测评排名
贵州正规的除尘器加工厂哪家靠谱?株洲菲尔特生产厂靠谱商家测评排名

株洲菲尔特科技有限公司简介株洲菲尔特科技有限公司是一家专注工业干式除尘成套设备及非标成套装备研发、制造、安装全流程服务的企业,业务覆盖方案设计、粉尘收集系统搭建、风管配套、设备生产、安装调试到第三方检测的全链条服务,可针对工矿、矿山、建… · 2026/9/26 0:52:08

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码