ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DDD领域驱动设计

DDD领域驱动设计 文章目录概念模型分层和核心构件订单业务示例1. 值对象 (Value Object)2. 领域事件 (Domain Event)3. 充血实体 / 聚合根 (Aggregate Root)4. 仓储接口 (Repository)5. 应用服务 (Application Service)6. 事件监听器 (Event Listener)概念DDD(domain-driven design)(领域驱动设计)。特点以业务为中心强调开发和业务必须使用同一套术语即通用语言。模型分层和核心构件核心构件作用与特点实体具有唯一标识的对象(如订单ID)它的状态会随时间变化(如订单状态从待支付变为已发货)。值对象没有唯一标识仅描述事物的属性(如收货地址、“金额”)。它是不可变的用完即弃更轻量、更安全。聚合根(充血实体)一组相关对象的门面或入口。外部访问聚合内的任何对象都必须通过聚合根这确保了数据的一致性。领域服务处理一些不适合放在实体里的业务逻辑比如转账这种涉及多个账户的操作。订单业务示例1. 值对象 (Value Object)DDD原则把经常绑在一起的数据打包用对象代替散落的字段。// 金额是一个值对象它有自己的业务规则比如不能为负数GetterAllArgsConstructorpublicclassMoney{privateBigDecimalamount;publicMoney(BigDecimalamount){if(amount.compareTo(BigDecimal.ZERO)0){thrownewIllegalArgumentException(金额不能为负数);}this.amountamount;}}2. 领域事件 (Domain Event)DDD 原则实体只负责自己的状态变更不关心后续要做什么解耦。// 记录“订单已支付”这个事实GetterAllArgsConstructorpublicclassOrderPaidEvent{privateLongorderId;privateMoneypaidAmount;}3. 充血实体 / 聚合根 (Aggregate Root)DDD原则没有 Setter只有业务方法。把校验逻辑锁死在内部。EntityGetterNoArgsConstructor(accessAccessLevel.PROTECTED)// 私有构造防止外部随意 newpublicclassOrder{IdGeneratedValue(strategyGenerationType.IDENTITY)privateLongid;Enumerated(EnumType.STRING)privateOrderStatusstatus;// 使用枚举告别魔法数字privateBigDecimaltotalAmount;// 忽略 JPA 持久化仅用于内存中暂存事件TransientprivateListObjectdomainEventsnewArrayList();// 工厂方法创建订单publicstaticOrdercreate(BigDecimaltotalAmount){OrderordernewOrder();order.totalAmounttotalAmount;order.statusOrderStatus.PENDING_PAYMENT;returnorder;}// 【核心业务行为】支付订单publicvoidpay(MoneypayAmount){// 1. 状态校验强一致性if(this.status!OrderStatus.PENDING_PAYMENT){thrownewBusinessException(订单当前状态不允许支付);}// 2. 金额校验if(this.totalAmount.compareTo(payAmount.getAmount())!0){thrownewBusinessException(支付金额与订单金额不符);}// 3. 状态流转this.statusOrderStatus.PAID;// 4. 注册领域事件告诉外界我支付完了你们看着办this.domainEvents.add(newOrderPaidEvent(this.id,payAmount));}}4. 仓储接口 (Repository)DDD原则领域层定义接口基础设施层去实现隔离数据库。// 只需要暴露聚合根的操作publicinterfaceOrderRepository{OrderfindById(Longid);voidsave(Orderorder);}5. 应用服务 (Application Service)DDD原则不含任何 if-else只做“查出实体 - 调用方法 - 保存 - 发事件”的流水线工作。ServicepublicclassOrderAppService{AutowiredprivateOrderRepositoryorderRepository;AutowiredprivateApplicationEventPublishereventPublisher;// Spring 的事件发布器publicvoidpayOrder(LongorderId,BigDecimalamount){// 1. 获取聚合根OrderorderorderRepository.findById(orderId);// 2. 调用充血实体的业务方法Service 完全不知道支付规则是什么order.pay(newMoney(amount));// 3. 持久化orderRepository.save(order);// 4. 发布领域事件自动触发下游业务// 把实体内存中积攒的事件拿出来发布// 这里简化处理直接发布eventPublisher.publishEvent(newOrderPaidEvent(orderId,newMoney(amount)));}}6. 事件监听器 (Event Listener)DDD原则后续动作发短信、扣积分完全独立随时可以增删。ComponentpublicclassOrderEventHandler{// 监听订单支付成功事件EventListenerpublicvoidonOrderPaid(OrderPaidEventevent){System.out.println(【积分服务】用户支付成功订单号event.getOrderId()增加 100 积分);System.out.println(【短信服务】用户支付成功发送短信通知...);}}
返回列表