背景
文章目标
领域驱动设计(DDD)概述
DDD 是一种以业务领域为核心的建模方法,它主张从实际业务问题中提炼出领域模型,并借助与业务专家共同构建的“普适语言”,确保开发人员与业务人员在同一概念体系下沟通与协作。
核心目标
实体(Entity)
值对象(Value Object)
聚合(Aggregate)与聚合根
领域服务(Domain Service)
工厂(Factory)与仓储(Repository)
领域事件(Domain Event)
在这一部分,我们将深入探讨如何从底层原理到具体实现,构建出既能准确映射业务规则又具有高扩展性与低耦合性的系统架构。以下内容不仅解释了专业术语,还通过详细示例说明了各个设计模式与架构风格的具体实现。
实体(Entity)
值对象(Value Object)
聚合(Aggregate)与聚合根
领域服务(Domain Service)
工厂模式(Factory)
仓储模式(Repository)
本章节通过订单管理系统这一具体案例,详细说明如何运用领域驱动设计(DDD)的思想,从业务需求分析到系统架构拆解,再到核心代码实现及解释,帮助读者清晰理解如何将理论落地到实际应用中。
订单创建
支付处理
订单变更
领域事件
为满足上述业务需求,我们将系统划分为以下主要组件,各组件职责明确、相互协作:
表现层(Presentation Layer)
应用层(Application Layer)
领域层(Domain Layer)
基础设施层(Infrastructure Layer)
集成层(Integration Layer)
在此部分,我们以关键代码示例详细解析如何通过代码实现订单管理系统的核心业务逻辑。
职责说明:
聚合根(Order)是整个订单生命周期的入口,负责管理订单状态的转换、协调内部订单项等子对象,并在关键操作时触发领域事件。
技术细节:
示例代码(伪代码示例):
public class Order {
private String orderId;
private String userId;
private OrderStatus status;
private List<OrderItem> items;
private BigDecimal totalAmount;
private List<DomainEvent> domainEvents = new ArrayList<>();
// 构造函数:生成唯一订单ID、初始化状态、记录创建时间
public Order(String userId) {
this.orderId = UUID.randomUUID().toString();
this.userId = userId;
this.status = OrderStatus.CREATED;
this.items = new ArrayList<>();
this.totalAmount = BigDecimal.ZERO;
// 触发订单创建领域事件
domainEvents.add(new OrderCreatedEvent(orderId, userId, LocalDateTime.now()));
}
// 添加订单项并更新总金额
public void addItem(OrderItem item) {
items.add(item);
totalAmount = totalAmount.add(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())));
}
// 支付订单:状态转换、领域事件触发
public void pay(PaymentInfo paymentInfo) {
if (!status.equals(OrderStatus.CREATED)) {
throw new IllegalStateException("订单状态不允许支付");
}
status = OrderStatus.PAID;
domainEvents.add(new OrderPaidEvent(orderId, paymentInfo.getPaymentId(), LocalDateTime.now()));
}
// 取消订单:状态转换、领域事件触发
public void cancel() {
if (!status.equals(OrderStatus.CREATED)) {
throw new IllegalStateException("订单状态不允许取消");
}
status = OrderStatus.CANCELLED;
domainEvents.add(new OrderCancelledEvent(orderId, LocalDateTime.now()));
}
// Getter 方法略
}
职责说明:
值对象用于描述订单的具体属性,例如订单项记录了产品ID、数量与单价;支付信息记录了支付单号、金额及支付方式。
技术细节:
示例代码:
public class OrderItem {
private final String productId;
private final int quantity;
private final BigDecimal price;
public OrderItem(String productId, int quantity, BigDecimal price) {
this.productId = productId;
this.quantity = quantity;
this.price = price;
}
// Getter 方法略
}
public class PaymentInfo {
private final String paymentId;
private final BigDecimal amount;
private final PaymentMethod method;
public PaymentInfo(String paymentId, BigDecimal amount, PaymentMethod method) {
this.paymentId = paymentId;
this.amount = amount;
this.method = method;
}
// Getter 方法略
}
职责说明:
领域事件用于记录订单状态的关键变更,如订单创建、支付和取消。
技术细节:
示例代码:
public abstract class DomainEvent {
private final LocalDateTime occurredOn;
public DomainEvent() {
this.occurredOn = LocalDateTime.now();
}
public LocalDateTime getOccurredOn() {
return occurredOn;
}
}
public class OrderCreatedEvent extends DomainEvent {
private final String orderId;
private final String userId;
public OrderCreatedEvent(String orderId, String userId, LocalDateTime occurredOn) {
super();
this.orderId = orderId;
this.userId = userId;
}
// Getter 方法略
}
// 同理,定义 OrderPaidEvent 和 OrderCancelledEvent
职责说明:
领域服务负责协调聚合根和其他领域对象,处理订单创建、支付、取消等业务流程,并与仓储进行交互,实现数据的持久化。
技术细节:
示例代码:
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
// 创建订单,添加订单项并持久化
public Order createOrder(String userId, List<OrderItem> items) {
Order order = new Order(userId);
for (OrderItem item : items) {
order.addItem(item);
}
orderRepository.save(order);
// 可发布 order.getDomainEvents() 到事件总线
return order;
}
// 处理订单支付
public void payOrder(String orderId, PaymentInfo paymentInfo) {
Order order = orderRepository.findById(orderId);
if (order == null) {
throw new IllegalArgumentException("订单不存在");
}
order.pay(paymentInfo);
orderRepository.save(order);
// 可发布支付领域事件
}
// 处理订单取消
public void cancelOrder(String orderId) {
Order order = orderRepository.findById(orderId);
if (order == null) {
throw new IllegalArgumentException("订单不存在");
}
order.cancel();
orderRepository.save(order);
// 可发布取消领域事件
}
}
订单创建流程
OrderService.createOrder()
,创建订单聚合根,并添加订单项。OrderCreatedEvent
,该事件异步通知库存或通知服务。支付与订单状态变更
OrderService.payOrder()
。CREATED
转为 PAID
,领域事件 OrderPaidEvent
被触发,通知后续财务、物流等模块。订单取消流程
OrderService.cancelOrder()
,订单状态更新为 CANCELLED
。OrderCancelledEvent
,后续系统进行库存回滚、退款处理。DDD 在微服务划分中的作用
明确服务边界
DDD 通过划分限界上下文,将复杂业务领域拆分成多个子领域,为微服务的划分提供理论依据。每个子领域都拥有独立的领域模型,确保各服务之间高度内聚、低耦合。
内部模型设计与业务协同
在每个微服务内部,DDD 强调构建领域模型(实体、值对象、聚合根等),通过普适语言促进业务专家与技术团队之间的高效沟通。这种方式帮助团队准确捕捉业务规则,从而指导微服务内部的设计与实现。
微服务架构的实现目标
服务自治与独立部署
微服务架构将整个系统拆分成多个独立部署的服务,每个服务专注于单一业务能力,实现自治管理。这样不仅提高了系统灵活性,也便于针对不同服务进行独立扩展和运维。
技术灵活性
由于服务之间松耦合,开发团队可以根据业务需要选择不同的技术栈,独立演进。DDD 的限界上下文理念帮助确保每个微服务内部领域模型的纯粹性,从而减少跨服务依赖带来的复杂性。
“DDD 是否就是微服务?”
疑问解析
尽管 DDD 与微服务在实践中常常结合使用,但两者关注点不同:
解决方案
将 DDD 作为划分微服务边界的理论基础,通过限界上下文明确每个服务的职责,从而实现业务逻辑与技术实现的双重解耦。
封装技术细节是否会引入冗余服务?
疑问解析
在设计过程中,如果领域模型和限界上下文划分不精准,可能出现不同服务实现相似业务逻辑,从而产生冗余。
解决方案
无状态函数的应用与好处
对比项目 | 传统三层架构 | 领域驱动设计(DDD) |
---|---|---|
实体 | - 通常将业务实体定义为 POJO,数据结构简单 - 业务规则主要集中在 Service 层处理 |
- 领域模型中的 Entity,不仅保存数据,还内嵌业务规则和状态转换 - 使领域对象更“聪明”,负责自身一致性 |
业务逻辑处理 | - 主要集中在业务逻辑层(Service),依赖多个简单实体 - 逻辑处理较为集中和单一 |
- 分布在实体、值对象、聚合和领域服务中 - 聚合根负责维护内部一致性,通过领域服务处理跨聚合操作 |
数据访问 | - Mapper/DAO 层负责与数据库交互,实现数据持久化和 CRUD 操作 - 实现较薄弱,主要关注数据读写 |
- 采用仓储(Repository)模式抽象数据访问 - 确保领域层与持久化技术解耦,保持领域模型纯粹性 |
高内聚、低耦合的系统构建
高内聚:指系统内部各模块、组件围绕单一业务目标组织,职责单一,内部关系紧密。例如,订单聚合根(Order)集中管理与订单相关的所有业务规则(状态转换、领域事件触发等),使得整个订单模型清晰而一致。
低耦合:指模块之间依赖尽可能减少,相互之间通过明确接口(如仓储接口、领域服务)进行交互,降低变更对系统其他部分的影响。通过限界上下文的划分,各个微服务或子系统可以独立演进,而不必担心外部依赖造成连锁问题。
领域模型、领域事件与限界上下文的价值
领域模型
领域事件
限界上下文(Bounded Context)
深度融合
DDD 与 DevOps
云原生与持续集成(CI/CD)
企业级应用数字化转型
架构演进路径
数字化转型
推广普适语言与领域建模
跨部门工作坊
文档与代码同步
完善限界上下文与跨服务协同
精细划分限界上下文
构建防腐层
自动化测试与监控
下面的表格对比了在领域驱动设计(DDD)和企业级开发中常见的几种 Java 对象及相关概念,帮助读者理解它们的定义、用途与特点,从而更好地区分和使用这些概念。
概念 | 定义 | 主要用途/特点 |
---|---|---|
POJO(Plain Old Java Object) | 纯粹的 Java 对象,不依赖于任何特定框架 | 简单数据结构表示,保持对象轻量性,作为基础构建块 |
Entity(实体) | 具有唯一标识和生命周期的业务对象 | 代表核心业务概念(如订单、用户),负责维护业务状态和身份一致性 |
Domain(领域) | 业务领域的整体模型,包括实体、值对象、领域服务等 | 完整表达业务规则和流程,是企业级系统的核心思想集合 |
Value Object(值对象,VO) | 无唯一标识、不可变的对象 | 用于描述属性组合(如地址、货币),确保数据的一致性和不可变性 |
DTO(数据传输对象) | 仅用于跨层传递数据的简单对象 | 不包含业务逻辑,主要在表现层与服务层或不同系统间交换数据时使用 |
Domain Service(领域服务) | 处理跨实体或不归属单一对象的业务逻辑的无状态服务 | 协调复杂业务规则,通常不持有状态,便于并行处理和单元测试 |
Repository(仓储) | 提供领域对象持久化和检索的抽象接口 | 解耦领域模型与底层数据存储,实现数据访问的统一管理 |
Aggregate & Aggregate Root(聚合与聚合根) | 聚合是相关对象的组合,聚合根是对外暴露的唯一入口 | 确保聚合内对象的一致性,集中管理业务规则和状态转换 |
Domain Event(领域事件) | 记录和传播领域内重要业务状态变更的事件 | 支持异步处理和跨服务通知,帮助实现事件溯源和系统解耦 |
Domain Factory(领域工厂) | 封装创建复杂领域对象的逻辑的组件 | 确保领域对象在创建时满足一致性和业务规则,隐藏复杂的实例化过程 |
说明