DDD学习第1课项目介绍与DDD分层 为什么需要 DDD传统开发方式往往是先做数据库再写 CRUD规则散落在 Controller / Service / Mapper无法表达业务领域系统越做越乱DDD 要解决的问题是让代码结构与业务领域结构保持一致让领域逻辑“有家可归”。当团队规模变大、业务复杂时DDD 的价值会指数级提升。项目背景订餐系统Order System用户可以在系统中浏览菜单创建订单添加菜品支付订单查看订单状态整体课程规划课次主题目标涉及概念1项目介绍与DDD分层建立项目结构理解限界上下文Bounded Context, Layered Architecture2建立领域模型识别实体和值对象Entity, Value Object3设计聚合与聚合根定义聚合边界Aggregate, Aggregate Root4仓储与持久化封装数据访问Repository Pattern5应用层服务组织业务用例Application Service6领域事件与事件驱动解耦聚合间依赖Domain Event7CQRS与查询模型分离读写模型CQRS8整合与运行启动应用、演示完整流程Integration, Use Case Flow第1课项目介绍与DDD分层目标理解 DDD 的分层结构构建项目骨架确定领域与限界上下文选择技术栈层级框架 / 技术应用层ApplicationSpring Boot Service领域层Domain纯 Java无依赖基础设施层InfrastructureSpring Data / InMemory 实现接口层InterfaceREST Controller项目结构order-system/ └── src/main/java/com/example/ordersystem/ ├── application/ 应用层只负责“用例”编排不写业务规则 │ └── order/ │ └── CreateOrderService.java // 下单用例服务参数校验→调领域→持久化→返回DTO │ ├── domain/ 领域层纯业务逻辑完全不依赖框架、数据库 │ └── order/ │ ├── model/ │ │ ├── Order.java // 聚合根整张订单含状态、总金额、行为 │ │ ├── OrderItem.java // 订单行商品SKU、数量、单价小计 │ │ ├── OrderId.java // 值对象订单ID封装格式校验与生成策略 │ │ └── Money.java // 值对象金额解决浮点精度、货币单位问题 │ └── repository/ │ └── OrderRepository.java // 领域仓库接口定义“存取订单”的DSL不关心技术实现 │ ├── infrastructure/ 基础设施层技术细节随时可替换 │ └── repository/ │ └── InMemoryOrderRepository.java // 内存实现MapOrderId,Order给测试/演示用 │ │ ├── interfaces/ 接口层对外暴露的任何协议REST、MQ、调度… │ └── api/ │ └── OrderController.java // RESTful入口接收JSON转DTO调应用服务转VO返回 │ └── OrderSystemApplication.java // SpringBoot启动类扫包、AutoConfiguration、启动容器业务域介绍订餐系统Food Ordering System通常订餐系统包含菜单管理下单与结算支付出餐与备餐配送用户系统评价系统库存系统但作为一个单课或小型系统我们不会一次做全部而是做一件以“订单上下文”作为主上下文进行 DDD 实战。建立统一语言Ubiquitous Language统一语言的意义业务人员与开发使用同一套核心术语不同概念不能混用模型与代码严格对应统一语言下面是我们订餐系统的统一语言统一语言表术语含义领域分类菜单Menu某个门店当前可售菜品列表Menu 聚合菜品MenuItem单个可点菜品如“炒饭”“可乐”值对象订单Order顾客提交的购买请求Order 聚合订单项OrderItem订单中的单个菜品及数量实体金额Money代表一笔金额值对象订单总价TotalAmount所有订单项的小计总和领域属性状态OrderStatus订单生命周期状态枚举聚合Aggregate领域中强一致性的边界DDD 概念支付Pay用户完成支付行为Domain Event 来源完成Complete订单流转到最终状态Domain Event 来源后续所有领域代码都基于这些术语建立。识别限界上下文Bounded ContextDDD 建模的第一步不是写代码而是划定业务范围即“边界上下文”。一个订餐系统至少包含常见上下文划分真实系统上下文BC职责Menu BC菜单、菜品、价格维护Order BC创建订单、订单生命周期、聚合根Payment BC支付交易、对接支付渠道Inventory BC库存检查与扣减Delivery BC派单、配送、路线优化User BC用户资料与会员体系本课程聚焦的上下文【Order BC】 ← 我们的主战场为什么选择它订单有清晰的聚合边界Order → OrderItem涉及状态机Created → Paid → Confirmed → Completed有跨上下文协作库存、菜单、支付有典型的领域事件OrderPaid、OrderCompleted更容易展示 CQRS、事件驱动、Repository 模式代码实现pom.xml使用 Spring Boot Java 8projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.example/groupIdartifactIdorder-system/artifactIdversion1.0.0/versionpackagingjar/packagingparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.4.10-SNAPSHOT/version/parentpropertiesjava.version8/java.version/propertiesdependencies!-- Spring Boot 基础依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- 测试 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/projectOrderSystemApplication.javapackagecom.example.ordersystem;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassOrderSystemApplication{publicstaticvoidmain(String[]args){SpringApplication.run(OrderSystemApplication.class,args);}}领域模型第一个实体Order.javapackagecom.example.ordersystem.domain.order.model;importjava.util.ArrayList;importjava.util.List;importjava.util.UUID;publicclassOrder{privatefinalOrderIdid;privatefinalListOrderItemitemsnewArrayList();privateMoneytotalAmountMoney.zero();publicOrder(OrderIdid){this.idid;}publicvoidaddItem(Stringname,intquantity,doubleprice){OrderItemitemnewOrderItem(name,quantity,newMoney(price));items.add(item);totalAmounttotalAmount.add(item.subtotal());}publicOrderIdgetId(){returnid;}publicMoneygetTotalAmount(){returntotalAmount;}publicListOrderItemgetItems(){returnitems;}}OrderItem.javapackagecom.example.ordersystem.domain.order.model;publicclassOrderItem{publicStringname;publicintquantity;publicMoneyprice;publicOrderItem(Stringname,intquantity,Moneyprice){this.namename;this.quantityquantity;this.priceprice;}publicMoneysubtotal(){returnprice.multiply(quantity);}}Money.javapackagecom.example.ordersystem.domain.order.model;publicclassMoney{privatefinaldoubleamount;publicMoney(doubleamount){this.amountamount;}publicstaticMoneyzero(){returnnewMoney(0);}publicMoneyadd(Moneyother){returnnewMoney(this.amountother.amount);}publicMoneymultiply(intfactor){returnnewMoney(this.amount*factor);}publicdoublegetAmount(){returnamount;}OverridepublicStringtoString(){returnString.format(%.2f,amount);}}OrderId.javapackagecom.example.ordersystem.domain.order.model;importjava.util.UUID;publicclassOrderId{privatefinalStringvalue;publicOrderId(Stringvalue){this.valuevalue;}publicstaticOrderIdnewId(){returnnewOrderId(UUID.randomUUID().toString());}publicStringgetValue(){returnvalue;}}仓储接口OrderRepository.javapackagecom.example.ordersystem.domain.order.repository;importcom.example.ordersystem.domain.order.model.Order;importcom.example.ordersystem.domain.order.model.OrderId;publicinterfaceOrderRepository{voidsave(Orderorder);OrderfindById(OrderIdid);}内存仓储实现InMemoryOrderRepository.javapackagecom.example.ordersystem.infrastructure.repository;importcom.example.ordersystem.domain.order.model.Order;importcom.example.ordersystem.domain.order.model.OrderId;importcom.example.ordersystem.domain.order.repository.OrderRepository;importorg.springframework.stereotype.Repository;importjava.util.concurrent.ConcurrentHashMap;RepositorypublicclassInMemoryOrderRepositoryimplementsOrderRepository{privatefinalConcurrentHashMapString,OrderstoragenewConcurrentHashMap();Overridepublicvoidsave(Orderorder){storage.put(order.getId().getValue(),order);}OverridepublicOrderfindById(OrderIdid){returnstorage.get(id.getValue());}}应用层服务CreateOrderService.javapackagecom.example.ordersystem.application.order;importcom.example.ordersystem.domain.order.model.Order;importcom.example.ordersystem.domain.order.model.OrderId;importcom.example.ordersystem.domain.order.repository.OrderRepository;importorg.springframework.stereotype.Service;ServicepublicclassCreateOrderService{privatefinalOrderRepositoryrepository;publicCreateOrderService(OrderRepositoryrepository){this.repositoryrepository;}publicOrdercreateSimpleOrder(){OrderordernewOrder(OrderId.newId());order.addItem(Fried Rice,1,12.5);order.addItem(Coke,2,3.0);repository.save(order);returnorder;}}REST 接口层OrderController.javapackagecom.example.ordersystem.interfaces.api;importcom.example.ordersystem.application.order.CreateOrderService;importcom.example.ordersystem.domain.order.model.Order;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassOrderController{privatefinalCreateOrderServicecreateOrderService;publicOrderController(CreateOrderServicecreateOrderService){this.createOrderServicecreateOrderService;}GetMapping(/orders/create)publicOrdercreateOrder(){returncreateOrderService.createSimpleOrder();}}运行与测试启动后访问http://localhost:8080/orders/create你将得到一个 JSON 输出{id:{value:7b12c...},items:[{name:Fried Rice,quantity:1,price:{amount:12.5}},{name:Coke,quantity:2,price:{amount:3.0}}],totalAmount:{amount:18.5}}第1课总结已经完成建立DDD基础架构明确分层结构领域 / 应用 / 基础设施 / 接口实现一个简单用例创建订单