当前位置: 首页 > article >正文

【架构实战】DDD领域驱动设计:从战略到战术

一、DDD概述领域驱动设计Domain-Driven DesignDDD是一种软件设计方法论DDD核心思想将业务领域知识作为软件设计的核心通过深入理解业务来构建领域模型让软件更好地反映业务本质DDD的价值解决复杂业务系统的设计问题提高代码的可维护性和可扩展性促进业务人员与技术人员的沟通二、DDD核心概念1. 领域Domain┌─────────────────────────────────────────────────────────────┐ │ 领域 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 子域1 │ │ 子域2 │ │ 子域3 │ │ │ │ (支撑子域) │ │ (核心子域) │ │ (通用子域) │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘子域类型核心域Core Domain业务的核心竞争力支撑子域Supporting Subdomain支撑核心业务的领域通用子域Generic Subdomain通用的、通用的领域2. 限界上下文Bounded Context┌──────────────────┐ ┌──────────────────┐ │ 订单上下文 │ │ 库存上下文 │ │ │ │ │ │ - Order │────▶│ - Inventory │ │ - OrderItem │ │ - Stock │ │ - Customer │ │ - Warehouse │ │ │ │ │ │ 统一语言订单 │ │ 统一语言库存 │ └──────────────────┘ └──────────────────┘限界上下文的作用明确模型的边界定义团队的职责保持语言的统一性三、战略设计1. 战略建模流程业务分析 → 识别限界上下文 → 定义上下文映射 → 战略设计输出2. 上下文映射上下文映射关系// 订单上下文上游publicinterfaceOrderService{OrdercreateOrder(OrderDTOdto);// 暴露给其他上下文的服务OrderSnapshotgetOrderSnapshot(LongorderId);}// 库存上下文下游- 通过防腐层访问ComponentpublicclassInventoryFacade{AutowiredprivateOrderServiceorderService;// 远程调用AutowiredprivateAntiCorruptionLayeracl;// 防腐层publicbooleanreserveStock(LongorderId){// 获取订单上下文的数据OrderSnapshotorderorderService.getOrderSnapshot(orderId);// 转换为自己上下文的实体OrderItemsitemsacl.toOrderItems(order);// 调用本上下文的服务returninventoryService.reserve(items);}}// 防腐层隔离不同上下文的模型差异ComponentpublicclassAntiCorruptionLayer{publicOrderItemstoOrderItems(OrderSnapshotsnapshot){returnOrderItems.builder().productId(snapshot.getProductId()).quantity(snapshot.getQuantity()).build();}}3. 上下文映射类型映射类型说明耦合度共享内核两个上下文共享部分模型高客户-供应商上游提供服务下游消费中跟随者跟随上游变化高防腐层隔离转换低开放主机服务提供公开API低独立方式彻底解耦最低四、战术设计1. 聚合Aggregate// 订单聚合根EntitypublicclassOrderextendsAggregateRoot{IdprivateOrderIdid;privateCustomerIdcustomerId;EmbeddedprivateOrderStatusstatus;OneToMany(cascadeCascadeType.ALL)privateListOrderItemitemsnewArrayList();privateMoneytotalAmount;// 聚合根负责维护内部一致性publicvoidaddItem(Productproduct,intquantity){// 业务规则检查if(status!OrderStatus.DRAFT){thrownewBusinessException(只有草稿状态的订单可以添加商品);}OrderItemitemOrderItem.builder().productId(product.getId()).productName(product.getName()).price(product.getPrice()).quantity(quantity).build();items.add(item);recalculateTotal();}publicvoidsubmit(){// 业务规则if(items.isEmpty()){thrownewBusinessException(订单不能为空);}this.statusOrderStatus.SUBMITTED;this.submittedAtLocalDateTime.now();// 发布领域事件registerEvent(newOrderSubmittedEvent(this));}privatevoidrecalculateTotal(){this.totalAmountitems.stream().map(item-item.getPrice().multiply(item.getQuantity())).reduce(Money.ZERO,Money::add);}}// 值对象EmbeddablepublicclassMoney{privateBigDecimalamount;privateStringcurrency;publicMoneymultiply(intquantity){returnnewMoney(this.amount.multiply(BigDecimal.valueOf(quantity)),this.currency);}publicstaticMoneyadd(Moneya,Moneyb){returnnewMoney(a.amount.add(b.amount),a.currency);}}2. 实体Entity// 实体有唯一标识的对象publicclassProduct{IdprivateProductIdid;privateStringname;privateMoneyprice;privateProductStatusstatus;// 实体的相等性基于IDOverridepublicbooleanequals(Objecto){if(thiso)returntrue;if(onull||getClass()!o.getClass())returnfalse;Productproduct(Product)o;returnObjects.equals(id,product.id);}OverridepublicinthashCode(){returnObjects.hash(id);}}// 标识对象EmbeddablepublicclassProductId{privateStringvalue;publicstaticProductIdof(Stringvalue){returnnewProductId(value);}}3. 领域服务Domain Service// 领域服务不属于任何实体的业务逻辑ServiceDomainServicepublicclassOrderDomainService{// 跨多个聚合的业务逻辑publicvoidtransferOrder(LongorderId,CustomerIdnewCustomerId){OrderorderorderRepository.findById(orderId).orElseThrow(()-newEntityNotFoundException(Order not found));// 业务规则if(order.getStatus()!OrderStatus.DRAFT){thrownewBusinessException(只有草稿订单可以转让);}// 检查新客户是否有未完成的订单if(customerService.hasPendingOrder(newCustomerId)){thrownewBusinessException(该客户有待处理订单);}order.changeCustomer(newCustomerId);orderRepository.save(order);}}4. 领域事件Domain Event// 领域事件publicclassOrderSubmittedEventextendsDomainEvent{privatefinalOrderIdorderId;privatefinalCustomerIdcustomerId;privatefinalMoneytotalAmount;publicOrderSubmittedEvent(Orderorder){super(EventId.generate(),LocalDateTime.now());this.orderIdorder.getId();this.customerIdorder.getCustomerId();this.totalAmountorder.getTotalAmount();}// Getter...}// 聚合根发布事件publicabstractclassAggregateRoot{privateListDomainEventdomainEventsnewArrayList();protectedvoidregisterEvent(DomainEventevent){domainEvents.add(event);}publicListDomainEventpullDomainEvents(){ListDomainEventeventsnewArrayList(domainEvents);domainEvents.clear();returnevents;}}// 事件发布处理器ComponentpublicclassDomainEventPublisher{AutowiredprivateApplicationEventPublisherpublisher;publicvoidpublish(DomainEventevent){// 发布到消息队列kafkaTemplate.send(domain-events,event.getClass().getSimpleName(),event);// 本地发布可选publisher.publishEvent(event);}}5. 仓储Repository// 仓储接口属于应用层但定义在领域层publicinterfaceOrderRepository{OptionalOrderfindById(OrderIdid);ListOrderfindByCustomerId(CustomerIdcustomerId);voidsave(Orderorder);voiddelete(OrderIdid);}// JPA实现RepositorypublicclassJpaOrderRepositoryimplementsOrderRepository{AutowiredprivateOrderJpaRepositoryjpaRepository;OverridepublicOptionalOrderfindById(OrderIdid){returnjpaRepository.findById(id.getValue()).map(this::toDomain);}Overridepublicvoidsave(Orderorder){OrderEntityentitytoEntity(order);jpaRepository.save(entity);}privateOrdertoDomain(OrderEntityentity){// 将实体转换为领域对象returnOrder.builder().id(OrderId.of(entity.getId())).status(entity.getStatus())// ... 转换其他字段.build();}}五、DDD分层架构1. 分层结构┌─────────────────────────────────────────────────────────────┐ │ 用户接口层 (Interface) │ │ Controllers, DTOs, Presenters, ViewModels │ ├─────────────────────────────────────────────────────────────┤ │ 应用层 (Application) │ │ Application Services, Commands, │ │ Queries, Event Handlers │ ├─────────────────────────────────────────────────────────────┤ │ 领域层 (Domain) │ │ Entities, Value Objects, Aggregates, Domain Services, │ │ Repositories (interfaces), Domain Events │ ├─────────────────────────────────────────────────────────────┤ │ 基础设施层 (Infrastructure) │ │ Repository Implementations, External Services, │ │ Message Publishers, Database Config │ └─────────────────────────────────────────────────────────────┘2. 代码结构com.example.ecommerce ├── interface # 接口层 │ ├── controller │ ├── dto │ └── presenter ├── application # 应用层 │ ├── command │ ├── query │ ├── service │ └── eventhandler ├── domain # 领域层 │ ├── model │ │ ├── order │ │ │ ├── Order.java │ │ │ ├── OrderItem.java │ │ │ ├── OrderId.java │ │ │ └── OrderStatus.java │ │ ├── product │ │ └── customer │ ├── service │ ├── repository │ └── event └── infrastructure # 基础设施层 ├── persistence │ ├── entity │ ├── dao │ └── repository ├── messaging └── external六、DDD实践案例1. 电商订单场景// 应用服务ServicepublicclassOrderApplicationService{AutowiredprivateOrderRepositoryorderRepository;AutowiredprivateProductRepositoryproductRepository;TransactionalpublicOrderDTOcreateOrder(CreateOrderCommandcommand){// 1. 创建订单聚合OrderorderOrder.create(command.getCustomerId());// 2. 添加商品for(OrderItemDTOitemDTO:command.getItems()){ProductproductproductRepository.findById(ProductId.of(itemDTO.getProductId())).orElseThrow(()-newEntityNotFoundException(Product not found));order.addItem(product,itemDTO.getQuantity());}// 3. 提交订单order.submit();// 4. 保存orderRepository.save(order);// 5. 返回DTOreturntoDTO(order);}}// DTOpublicclassOrderDTO{privateStringorderId;privateStringstatus;privateListOrderItemDTOitems;privateBigDecimaltotalAmount;// Getter/Setter...}2. 事件驱动协作// 订单提交事件监听ComponentpublicclassOrderEventHandler{AutowiredprivateInventoryServiceinventoryService;AutowiredprivateNotificationServicenotificationService;KafkaListener(topicsOrderSubmittedEvent)publicvoidhandleOrderSubmitted(OrderSubmittedEventevent){// 扣减库存inventoryService.reserveStock(event.getOrderId(),event.getItems());// 发送通知notificationService.notifyCustomer(event.getCustomerId(),订单已提交: event.getOrderId());}}七、DDD实施建议1. 实施步骤1. 业务调研 → 理解业务领域 2. 识别限界上下文 → 划分系统边界 3. 定义通用语言 → 统一团队沟通 4. 战略设计 → 定义上下文映射 5. 战术设计 → 实现领域模型 6. 持续重构 → 深化领域理解2. 常见问题问题解决方案DDD太复杂先从核心域开始逐步推广贫血模型将业务逻辑移到领域层滥用仓储仓储对应聚合非所有实体过度设计保持简单避免过度抽象3. 团队协作业务人员提供领域知识开发人员实现领域模型领域专家深入理解业务持续沟通保持语言统一八、总结DDD是一种强大的软件设计方法战略设计确定系统的边界和关系战术设计构建丰富的领域模型分层架构保持代码的清晰结构持续演进通过重构深化领域理解最佳实践从核心域开始逐步推广保持领域模型的纯粹性重视统一语言的建立通过事件驱动实现解耦个人观点仅供参考

相关文章:

【架构实战】DDD领域驱动设计:从战略到战术

一、DDD概述 领域驱动设计(Domain-Driven Design,DDD)是一种软件设计方法论: DDD核心思想: 将业务领域知识作为软件设计的核心通过深入理解业务来构建领域模型让软件更好地反映业务本质 DDD的价值: 解决复杂…...

C++ 多态编程与纯虚函数详解

C++ 多态编程与纯虚函数详解 多态(Polymorphism)是面向对象编程的核心特性之一,它允许同一接口表现出不同的行为。C++ 支持编译时多态(静态多态)和运行时多态(动态多态)。本文重点讲解运行时多态,以及实现它的关键工具——虚函数与纯虚函数。 一、多态的基本概念 静态…...

如何将影像组学特征与肿瘤微环境(免疫细胞浸润、核形态、PD-L1) 建立关联,以预测免疫治疗响应及预后

01导语各位同学,大家好。现在做影像组学,如果还只停留在“提取特征—建个模型—算个AUC”,那就有点像算命算得挺准,但为啥准,自己也说不明白。别人一问:你这特征到底代表啥?背后有啥道理&#x…...

Conda换源后还是安装失败?试试这个‘组合拳’:官方源+国内源+conda-forge的混合配置指南

Conda混合源配置实战:破解特殊包安装失败的终极方案 当你在深夜赶项目进度时,突然遇到PackagesNotFoundError的红色报错,即使已经配置了国内镜像源也无济于事——这种挫败感每个数据科学工作者都深有体会。传统教程只会教你单一地切换镜像源&…...

成都创意广告机构推荐与优势分析

成都创意广告机构推荐与优势分析1. 阿佩克思(Apex)阿佩克思作为成立于1993年的西部头部咨询机构,以其卓越的品牌服务和整合营销能力闻名于业界。与奥美、新希望等知名品牌的合作,使其在政府及企业战略咨询、品牌营销等领域具有了广…...

告别Eclipse臃肿!5分钟搞定VS Code搭建RISC-V开发环境(含GCC/OpenOCD配置)

告别Eclipse臃肿!5分钟搞定VS Code搭建RISC-V开发环境(含GCC/OpenOCD配置) 如果你正在寻找一种更轻量、更现代化的RISC-V开发体验,那么VS Code可能是你一直在等待的解决方案。与传统的Eclipse相比,VS Code以其快速的启…...

收藏!2026年AI工程师月薪20804元,16个岗位抢1人,小白/程序员必看的大模型赛道机遇

2026年AI工程师平均月薪达20804元,智能驾驶系统工程师供需比高达16:1。机器人、新材料、光电子行业职位数同比大幅增长,薪资普遍过万。产业升级推动新质生产力爆发,高薪背后是技术要求和人才紧缺,更是小白、程序员转型大模型领域的…...

终极指南:如何使用ncmdump轻松解密网易云音乐NCM文件

终极指南:如何使用ncmdump轻松解密网易云音乐NCM文件 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否曾经在网易云音乐下载了心爱的歌曲,却发现只能在特定播放器里播放?🎵 那些以…...

别再用OpenCV了!用Python的face_recognition库,5行代码搞定人脸识别(附完整项目)

5行代码解锁人脸识别新姿势:face_recognition库实战指南 当开发者第一次接触人脸识别技术时,往往会陷入OpenCV复杂的配置和冗长的代码中。但今天,我要告诉你一个秘密武器——face_recognition库,它能让你用5行核心代码完成OpenCV需…...

从UVM糖果教程到芯片验证:深入理解packer策略对象与$bits/$size的妙用

从UVM糖果教程到芯片验证:深入理解packer策略对象与$bits/$size的妙用 第一次看到UVM中的pack/unpack机制时,我正为一个跨时钟域验证问题头疼不已。传统的手动位拼接方式不仅容易出错,每次协议变更都需要重新计算偏移量。直到偶然翻看《UVM糖…...

终极深度配置指南:3种高效方法彻底掌握Windows风扇控制软件

终极深度配置指南:3种高效方法彻底掌握Windows风扇控制软件 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trendi…...

告别模块依赖:手把手教你将Qt6 MQTT库作为第三方库集成到任意项目

告别模块依赖:手把手教你将Qt6 MQTT库作为第三方库集成到任意项目 在物联网项目开发中,MQTT协议因其轻量级和高效性成为设备通信的首选方案。Qt作为跨平台开发框架,其官方提供的qtmqtt模块却常常让开发者陷入依赖管理的困境——传统安装到Qt系…...

不再停留在概念!金融垂直智能体,营销风控价值逐步兑现

今年以来,OpenClaw 小龙虾的横空出世,再度唤醒了社会大众对智能体助手的追捧,这一热门趋势也进一步延伸到金融行业。尽管像OpenClaw这样的智能体能够为金融机构提供更平价、易用的智能体落地痛到,但是碍于金融行业的强数据驱动、严…...

WarcraftHelper:魔兽争霸III终极增强插件完全指南

WarcraftHelper:魔兽争霸III终极增强插件完全指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸III的陈旧限制而烦恼吗&a…...

Qt信号槽传自定义类型踩坑记:qRegisterMetaType的正确打开方式(附完整代码)

Qt信号槽传自定义类型:从编译错误到深度实践的完全指南 第一次在Qt信号槽中使用自定义数据类型时,那个鲜红的错误提示框跳出来的时候,我盯着屏幕愣了三秒——明明代码逻辑完全正确,为什么连接信号槽时会报错?相信很多Q…...

STM32 ADC+高速DMA 采集原理与实战

一、核心概念1. 什么是 ADC?ADC 是模数转换器,作用是把模拟电压转换成数字值。STM32F103 的 ADC 是 12 位的,输出范围 0~4095,对应电压范围 0~3.3V,换算公式:电压 ADC值 3.3V / 4096。2. 什么是 DMA&…...

NX二次开发避坑指南:处理表达式(Expression)TAG时内存泄漏怎么办?

NX二次开发内存管理实战:表达式操作中的资源释放陷阱与解决方案 在NX二次开发领域,表达式(Expression)操作是构建参数化模型的核心技术之一。许多开发者能够熟练使用UF_MODL_ask_exps_of_feature等函数获取表达式数据,却常常忽视背后的内存管…...

终极Windows和Office智能激活方案:KMS_VL_ALL_AIO完整深度解析

终极Windows和Office智能激活方案:KMS_VL_ALL_AIO完整深度解析 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 你是否曾为Windows和Office的激活问题而烦恼?当系统频繁弹…...

别再死记硬背74HC138真值表了!用Arduino+面包板,5分钟搞懂3-8译码器怎么省IO口

用Arduino实战破解74HC138:3根线控制8个LED的硬件魔法 记得第一次在电子设计课上看到74HC138真值表时,那种面对16进制代码的茫然感至今难忘。直到某天在创客空间,看到有人用Arduino和面包板搭建了一个会"跑马"的LED阵列——只用3根…...

别再只写“人”看了!企业GEO优化的四大核心要素,让你的品牌成为AI的“默认答案”

AI不会因为你的文采而感动,它只关心能不能在0.1秒内从你的内容里挖出它要的数据和答案。最近和不少做技术出海和B2B营销的朋友聊天,大家都有一个共同的焦虑:内容发了不少,文案也打磨得很漂亮,逻辑结构也算清晰。但无论…...

告别单向控制:用RDM协议给你的DMX灯光系统做个‘体检’和‘点名’

告别单向控制:用RDM协议给你的DMX灯光系统做个‘体检’和‘点名’ 灯光控制系统的运维人员常常面临一个尴尬局面:当舞台上的灯具突然罢工时,你只能靠肉眼和经验去排查故障。传统DMX512协议的单向通信特性,让系统维护变成了"盲…...

如何搭建一个药品市场价格监控智能体来实现100%价格一致性? —— 2026全渠道价格均衡化架构实战指南

在2026年的医药流通领域,随着《关于健全药品价格形成机制的若干意见》的全面深化落实,药品价格监管已从“事后查处”转向“实时监测与动态预警”。 所谓的“100%价格一致性”,在当前政策语境下,并非指全国所有药店的药品价格必须分…...

三大主流推理框架如何选型--SGLang、KTransformers、vLLM

文章目录一、基础信息与核心定位1. vLLM2. SGLang3. KTransformers二、统一测试基准(数据可信前提)三、三大框架量化实测数据(关键支撑)1. 单轮普通对话(无重复上下文)2. 多轮对话 / 重复上下文&#xff08…...

专业相机连接SDK源码,为你的影像应用快速构建可靠传输基础

专业相机连接SDK源码,为你的影像应用快速构建可靠传输基础如果你正在开发图片直播、远程拍摄或自动化影像采集类应用,那么“相机与手机稳定传输”这个基础功能,一定是你无法绕过的技术门槛。今天,我们聊聊为什么选择一套成熟的相机…...

高通Camx架构实战:如何通过日志(Logcat)快速定位Camera启动失败问题

高通Camx架构实战:如何通过日志(Logcat)快速定位Camera启动失败问题 当你在调试高通平台的Camera模块时,是否遇到过这样的场景:应用调用了Camera API,但预览界面一片漆黑,或者直接抛出了Camera设…...

2026 年 7 款国产化企业级智能体横向对比:信创适配与落地能力测评

进入 2026 年,中国信创产业已从基础软硬件的“局部替代”全面迈向核心业务系统的“体系化升级”。在这一背景下,企业级智能体(AI Agent)不再仅仅是技术实验室中的原型,而是成为了驱动金融、能源、政务等关键行业数字化…...

SignalTap II高级玩法:多级触发与多次触发实战详解,精准捕捉复杂时序问题

SignalTap II高级玩法:多级触发与多次触发实战详解,精准捕捉复杂时序问题 调试FPGA设计就像在黑暗森林中寻找一只会隐形的萤火虫——你永远不知道它什么时候会出现,更不知道它会在哪个角落闪烁。SignalTap II作为Intel FPGA开发者的"夜视…...

text-ada-001 完整指南(含训练数据细节与停用说明)

text-ada-001 是 OpenAI 早期 GPT-3 系列中的入门级、超轻量文本生成模型,属于第一代 instruct 系列(后缀 -001),以速度快、成本低为核心优势,现已于 2024 年 1 月 4 日正式停用。该模型与同系列的 text-davinci-003、…...

CANoe Trace窗口保姆级配置指南:从列显示到颜色字体,打造你的专属分析视图

CANoe Trace窗口高阶配置实战:打造高效诊断视图的5个关键策略 在汽车电子系统开发与测试领域,CANoe的Trace窗口就像工程师的"听诊器",但大多数人只停留在基础使用层面。当面对复杂的车载网络数据流时,未经优化的Trace视…...

XGBoost损失函数原理与实战应用指南

1. 理解XGBoost损失函数的重要性在机器学习竞赛和工业实践中,XGBoost(eXtreme Gradient Boosting)长期占据着主导地位。这个强大的算法框架之所以能够持续保持优势,很大程度上得益于其灵活且高效的损失函数设计。损失函数就像是模…...