尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

第46篇-DDD战略设计-领域建模

第46篇-DDD战略设计-领域建模 【Kotlin Spring Boot 4 从零到架构师】第 46 篇DDD 战略设计 — 领域建模本系列定位零基础入门从 Kotlin 语法一路到 Spring Boot 4 高级架构DDD Modulith适合 Java 开发者转型也适合纯新手系统学习。本篇你将学到DDD领域驱动设计的核心思想与价值战略设计领域、子域、限界上下文统一语言Ubiquitous Language实体、值对象、聚合根的区别领域事件的概念学完本篇你将理解 DDD 不是一种代码技术而是一种用业务语言驱动软件设计的方法论。一、为什么需要 DDD1.1 传统开发的困境业务人员说用户下单后先扣库存再生成订单。 开发人员写的代码UserOrderService.createOrder() 问题 - 业务和技术说不同的语言沟通成本高 - 业务逻辑散落在 Service / Controller / Repository 中 - 随着业务增长代码变成「大泥球」1.2 DDD 的核心主张软件的核心价值 对业务领域的准确建模 不是「数据库驱动设计」先建表再写代码 而是「领域驱动设计」先理解业务再建模型最后落地到代码和数据库二、战略设计2.1 领域与子域领域Domain整个业务系统覆盖的范围。mini-shop 的领域 电商系统。子域Subdomain把大领域拆分成可管理的小块。电商领域 ├── 商品子域核心 ← 商品管理、库存、搜索 ├── 订单子域核心 ← 下单、支付、发货 ├── 用户子域支撑 ← 注册、登录、个人信息 ├── 通知子域通用 ← 邮件、短信 └── 统计子域通用 ← 报表、分析子域类型特点示例核心子域业务核心竞争力最值得投入商品、订单支撑子域必要但不是核心用户管理通用子域通用功能可用现成方案通知、日志下面用 Mermaid 图来直观展示电商领域的子域划分电商领域通用子域支撑子域核心子域通知子域商品子域订单子域用户子域统计子域2.2 限界上下文Bounded Context限界上下文是一个模型的边界——在这个边界内每个业务概念都有明确的、唯一的含义。商品这个词在不同上下文中含义不同 商品上下文Product Context Product { id, name, price, stock, category } 关注商品信息、库存 订单上下文Order Context OrderItem 中的 Product { productId, name, unitPrice } 关注购买时的快照名称和价格定格在购买那一刻 搜索上下文Search Context ProductDocument { id, name, category, score } 关注搜索相关性每个限界上下文有独立的模型不需要共享同一套实体类。上下文之间通过接口或事件通信。2.3 上下文映射Context Map描述限界上下文之间的关系┌──────────────┐ API 调用 ┌──────────────┐ │ Order │ ──────────→ │ Product │ │ Context │ 查询商品信息 │ Context │ └──────────────┘ └──────────────┘ │ │ │ 发布事件 │ 发布事件 ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ Notification │ │ Search │ │ Context │ │ Context │ └──────────────┘ └──────────────┘下面用 Mermaid 图来更清晰地展示各限界上下文之间的映射关系搜索上下文通知上下文商品上下文订单上下文API 调用查询商品信息发布事件OrderCreated发布事件ProductUpdatedOrder ContextProduct ContextNotification ContextSearch Context2.4 统一语言团队开发 产品 业务共同约定的词汇表贯穿业务文档到代码命名统一语言代码中的体现商品ProductProduct类订单OrderOrder类下单Place OrderplaceOrder()方法扣减库存Deduct StockdeductStock()方法已发货ShippedOrderStatus.SHIPPED核心原则代码中的命名应该和业务人员使用的词汇一致。不要出现业务人员说「下单」而代码写createRecord()这种不一致。三、核心构造块3.1 实体Entity有唯一标识的对象。即使属性完全相同ID 不同就是不同的实体。// Order 是实体——即使两个订单的金额、商品完全相同只要 ID 不同就是不同的订单classOrder(valid:Long,varstatus:OrderStatus,vartotalAmount:BigDecimal,valitems:ListOrderItem)特征有唯一标识ID可变属性可以修改生命周期内标识不变3.2 值对象Value Object没有唯一标识的对象完全由属性值定义。属性值相同的两个值对象是等价的。// Address 是值对象——两个地址相同的 Address 是等价的dataclassAddress(valprovince:String,valcity:String,valstreet:String,valzipCode:String)// Money 是值对象dataclassMoney(valamount:BigDecimal,valcurrency:String){operatorfunplus(other:Money):Money{require(currencyother.currency)returnMoney(amountother.amount,currency)}}特征没有标识靠属性值区分不可变val两个值相同的值对象可以互相替换Kotlin 的data class天然适合做值对象——自动生成equals/hashCode。3.3 聚合与聚合根Aggregate Root**聚合Aggregate**是一组相关对象的集合它们被视为一个整体进行数据修改。聚合根是聚合的入口点——外部只能通过聚合根操作聚合内的对象。Order 聚合 ┌───────────────────────────────────────┐ │ Order聚合根 │ │ ├── id: Long │ │ ├── status: OrderStatus │ │ ├── shippingAddress: Address值对象 │ │ ├── items: ListOrderItem │ │ │ ├── productId │ │ │ ├── quantity │ │ │ └── unitPrice │ │ └── totalAmount: Money值对象 │ └───────────────────────────────────────┘ 外部代码只能通过 Order 操作 items ✅ order.changeItemQuantity(productId, 5) ← 通过聚合根 ❌ orderItem.setQuantity(5) ← 绕过聚合根破坏封装聚合设计原则尽可能小的聚合只包含必须一起修改的对象通过 ID 引用其他聚合不要直接持有对象引用只持有 ID一个事务只修改一个聚合保证一致性下面用 Mermaid 图来直观展示 Order 聚合的结构containshashashas1111*111OrderLong idOrderStatus statusAddress shippingAddressListOrderItem itemsMoney totalAmountchangeItemQuantity(productId, quantity)OrderItemLong productIdint quantityMoney unitPriceAddressString provinceString cityString streetString zipCodeMoneyBigDecimal amountString currencyplus(other)3.4 领域事件Domain Event领域中发生的、业务关心的事件。// 订单已创建事件dataclassOrderCreatedEvent(valorderId:Long,valuserId:Long,valtotalAmount:BigDecimal,valoccurredAt:LocalDateTimeLocalDateTime.now())// 订单已支付事件dataclassOrderPaidEvent(valorderId:Long,valoccurredAt:LocalDateTimeLocalDateTime.now())事件是已发生的事实用过去式命名。其他模块可以订阅这些事件并做出反应。3.5 各构造块对比构造块标识可变性示例实体有唯一 ID可变Order、Product、User值对象无靠值区分不可变Address、Money聚合根有唯一 ID可变Order聚合的入口领域事件有事件 ID不可变OrderCreatedEvent四、mini-shop 领域模型分析4.1 识别限界上下文mini-shop 分为 4 个限界上下文 1. Product商品上下文 - 聚合根Product - 值对象Price - 实体ProductCategory 2. Order订单上下文 - 聚合根Order - 实体OrderItem - 值对象ShippingAddress、Money - 领域事件OrderCreated、OrderPaid、OrderShipped 3. User用户上下文 - 聚合根User - 值对象Email、PhoneNumber 4. Notification通知上下文 - 订阅 Order 上下文的事件 - 发送邮件/短信4.2 识别聚合Product 聚合 根Product 内部无子实体Price 是值对象 Order 聚合 根Order 内部OrderItem实体、ShippingAddress值对象 引用userId引用 User 聚合但不持有 User 对象 productId引用 Product 聚合只持有 ID4.3 统一语言词汇表中文 英文 类型 上下文 商品 Product 实体 Product 价格 Price 值对象 Product / Order 订单 Order 聚合根 Order 订单明细 OrderItem 实体 Order 收货地址 ShippingAddress 值对象 Order 下单 placeOrder 操作 Order 取消订单 cancelOrder 操作 Order 已发货 SHIPPED 状态 Order 库存不足 OutOfStock 异常 Product本篇小结知识点核心内容DDD领域驱动设计——业务驱动软件设计子域核心竞争力、支撑必要、通用现成方案限界上下文模型边界每个概念在边界内有唯一含义统一语言业务词汇贯穿到代码实体有唯一 ID可变值对象无 ID靠值区分不可变聚合根聚合的入口外部只能通过它操作领域事件已发生的事实用过去式命名聚合设计原则小聚合、ID 引用、一事务一聚合下篇预告第 47 篇DDD 战术设计 — 代码落地理论明白了代码怎么写下一篇把 DDD 概念落地为 Kotlin 代码分层架构、聚合根实现、Repository 模式、应用服务。如果本篇内容对你有帮助欢迎点赞收藏有任何疑问欢迎在评论区交流。
返回列表