目录
- [1. 简介](#1. 简介)
- [2. 基础概念](#2. 基础概念)
- [3. 实践(以后再写,先给出一个结构)](#3. 实践(以后再写,先给出一个结构))
- [4. 对比](#4. 对比)
-
- [4.1 DDD 与主流框架/架构的详细对比](#4.1 DDD 与主流框架/架构的详细对比)
-
- [4.1.1 DDD vs MVC 架构](#4.1.1 DDD vs MVC 架构)
- [4.1.2 DDD vs 传统分层架构(三层架构)](#4.1.2 DDD vs 传统分层架构(三层架构))
- [4.1.3 DDD vs Clean Architecture(整洁架构)](#4.1.3 DDD vs Clean Architecture(整洁架构))
- [4.1.4 DDD vs 微服务架构](#4.1.4 DDD vs 微服务架构)
- [4.1.5 DDD vs 传统技术框架(Spring Boot/MyBatis)](#4.1.5 DDD vs 传统技术框架(Spring Boot/MyBatis))
- [4.2 各类框架/架构的适用场景总结](#4.2 各类框架/架构的适用场景总结)
- [5. 总结](#5. 总结)
1. 简介
DDD (Domain-Driven Design,领域驱动设计)是由埃里克・埃文斯(Eric Evans)提出的面向复杂业务领域的软件设计方法论 ,核心思想是让软件模型与业务领域模型保持一致 ,通过统一的业务语言(Ubiquitous Language)消除技术与业务之间的沟通壁垒。
它并非一套现成的框架,而是一套设计原则、模式和思想体系,适用于业务逻辑复杂的系统(如金融、电商、医疗等),尤其适合团队协作中业务人员与技术人员的对齐。
依靠领域驱动设计的设计思想,通过事件风暴建立领域模型,合理划分领域逻辑和物理边界,建立领域对象及服务矩阵和服务架构图,定义符合DDD分层架构思想的代码结构模型,保证业务模型与代码模型的一致性。通过上述设计思想、方法和过程,指导团队按照DDD设计思想完成微服务设计和开发。
- 拒绝泥球小单体、拒绝污染功能与服务、拒绝一加功能排期一个月
- 架构出高可用极易符合互联网高速迭代的应用服务
- 物料化、组装化、可编排的服务,提高人效
2. 基础概念
一、DDD的核心思想前提
这是理解DDD的基础,决定了整个设计方法论的导向。
-
领域(Domain)
- 定义:软件要解决的特定业务问题范围,是业务的边界。
- 举例:电商领域、金融支付领域、物流仓储领域;一个电商领域又可细分为订单、商品、用户、支付等更小的业务范围。
- 核心:所有设计都围绕领域内的业务规则展开,而非技术实现。
-
通用语言(Ubiquitous Language)
- 定义:业务人员与技术人员共同认可、统一使用的业务术语体系,贯穿需求分析、设计、编码、测试全流程。
- 作用:消除"业务说的术语"和"代码中的命名"之间的鸿沟,比如业务说"订单履约",代码中就有
OrderFulfillmentService,而非模糊的OrderStatusUpdateService。 - 要求:团队沟通必须使用通用语言,禁止技术人员自创与业务无关的术语。
-
子领域(Subdomain)
- 定义:将大领域拆分为更小的、内聚的业务单元,每个子领域对应一个独立的业务能力。
- 分类(按业务重要性):
- 核心子领域 :系统的核心竞争力,如电商的订单交易子领域 、银行的核心账务子领域。
- 支撑子领域 :支持核心业务的辅助能力,如电商的用户认证子领域 、库存管理子领域。
- 通用子领域 :多个子领域复用的公共能力,如日志子领域 、权限子领域,可封装为公共组件。
二、DDD的核心领域建模概念
领域建模是DDD的核心,目的是将业务规则转化为可落地的代码模型,核心组件都集中在领域层。
- 实体(Entity)
- 定义:具有唯一标识、生命周期内状态可变的业务对象,其身份由ID决定,而非属性。是依托于持久化层数据以领域服务功能目标为指导设计的领域对象。持久化PO对象是原子类对象,不具有业务语义,而实体对象是具有业务语义且有唯一标识的对象,跟随于领域服务方法的全生命周期对象。如:用户PO持久化对象,会涵盖,用户的开户实体、授信实体、额度实体对象。也包括如商品下单时候的购物车实体对象。这个对象也通常是领域服务方法的入参对象。
- 核心特征:标识相等性 ------只要ID相同,即使属性不同,也是同一个实体。比如一个用户(
User),即使修改了昵称和手机号,只要用户ID不变,就是同一个用户。 - 代码特征:
- 必须有唯一标识字段(如
userId); - 重写
equals()和hashCode()方法,基于ID判断相等性; - 包含自身的业务行为方法(如
User.changePhoneNumber()),而非单纯的属性载体。
- 必须有唯一标识字段(如
java
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class OrderItem {
// 唯一标识:订单项ID
private Long orderItemId;
// 关联聚合根ID:订单ID(聚合间仅通过ID关联)
private Long orderId;
// 业务属性
private Long productId; // 商品ID
private String productName; // 商品名称
private Integer quantity; // 购买数量
private Long unitPrice; // 商品单价(单位:分)
// 订单项自身的业务逻辑:计算订单项总金额
public Long calculateItemTotalPrice() {
return (long) this.quantity * this.unitPrice;
}
}
/*
有唯一标识orderItemId,通过 ID 判断是否为同一个订单项;
包含自身业务方法calculateItemTotalPrice(计算订单项总金额),体现 "实体封装行为";
依赖订单聚合根存在(通过orderId关联),外部无法直接修改订单项,需通过订单聚合根操作。
*/
- 值对象(Value Object)
- 定义:无唯一标识、由属性值决定身份、不可变的业务对象,用于描述实体的属性。
- 核心特征:
- 属性相等性------所有属性值相同,就是同一个值对象;
- 不可变性------创建后属性不能修改,避免产生副作用;
- 无生命周期------不独立存在,依赖于实体或聚合。
- 举例:
Address(省、市、区、详细地址)、Money(金额、币种)、PhoneNumber(手机号)。 - 代码特征:类和属性用
final修饰,无setter方法,通过构造函数初始化所有属性。
java
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
// 不可变:类和属性用final,无setter
@Getter
@AllArgsConstructor // 构造函数初始化所有属性
@EqualsAndHashCode // 基于所有属性生成equals和hashCode(属性相等性)
public final class ShippingAddress {
// 收货地址属性
private final String province; // 省
private final String city; // 市
private final String district; // 区
private final String detail; // 详细地址
private final String receiver; // 收件人
private final String phone; // 联系电话
// 可选:添加业务校验逻辑(值对象自身负责属性合法性)
public static ShippingAddress create(String province, String city, String district, String detail, String receiver, String phone) {
if (province == null || province.trim().isEmpty()) {
throw new IllegalArgumentException("省份不能为空");
}
if (phone == null || !phone.matches("^1[3-9]\\d{9}$")) {
throw new IllegalArgumentException("手机号格式不正确");
}
return new ShippingAddress(province, city, district, detail, receiver, phone);
}
}
/*
用final修饰类和属性,确保不可变性,创建后无法修改属性;
@EqualsAndHashCode基于所有属性生成方法,两个ShippingAddress只要属性全相同,就是同一个对象;
提供静态创建方法create,负责属性合法性校验,保证值对象的有效性。
*/
- 聚合(Aggregate)与聚合根(Aggregate Root)
- 聚合 :一组紧密关联的领域对象的集合 ,作为一个统一的修改单元和数据一致性边界 。比如订单聚合包含
Order(订单)、OrderItem(订单项)、ShippingAddress(收货地址)。 - 聚合根 :聚合的根实体,是聚合对外的唯一访问入口,负责维护聚合内的业务规则和数据一致性。
- 聚合的核心设计规则 (必须严格遵守):
- 外部对象只能通过聚合根访问聚合内的其他对象,不能直接操作聚合内的非根对象(如不能直接修改
OrderItem,必须通过Order操作); - 聚合内的对象可以直接关联,聚合之间只能通过聚合根ID关联(避免跨聚合的复杂依赖);
- 聚合是数据持久化的最小单元------一次只能保存或修改一个聚合,确保聚合内的数据一致性。
- 外部对象只能通过聚合根访问聚合内的其他对象,不能直接操作聚合内的非根对象(如不能直接修改
- 聚合 :一组紧密关联的领域对象的集合 ,作为一个统一的修改单元和数据一致性边界 。比如订单聚合包含
java
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
public class Order {
// 聚合根唯一标识:订单ID
private Long orderId;
// 业务属性
private Long userId; // 用户ID
private OrderStatus orderStatus; // 订单状态
private Long totalAmount; // 订单总金额(单位:分)
private ShippingAddress shippingAddress; // 收货地址(值对象)
// 聚合内关联:订单项列表(直接关联实体)
private List<OrderItem> orderItems = new ArrayList<>();
// 聚合根自身业务逻辑:添加订单项(维护聚合内数据一致性)
public void addOrderItem(OrderItem orderItem) {
if (orderItem == null) {
throw new IllegalArgumentException("订单项不能为空");
}
// 关联当前订单ID
orderItem.setOrderId(this.orderId);
this.orderItems.add(orderItem);
// 添加订单项后,更新订单总金额
this.calculateTotalAmount();
}
// 聚合根自身业务逻辑:计算订单总金额
private void calculateTotalAmount() {
this.totalAmount = this.orderItems.stream()
.mapToLong(OrderItem::calculateItemTotalPrice)
.sum();
}
// 聚合根自身业务逻辑:取消订单(仅待支付状态可取消)
public void cancelOrder() {
if (this.orderStatus != OrderStatus.PENDING_PAYMENT) {
throw new IllegalStateException("仅待支付订单可取消");
}
this.orderStatus = OrderStatus.CANCELED;
}
// 订单状态枚举(通用语言)
public enum OrderStatus {
PENDING_PAYMENT, // 待支付
PAID, // 已支付
CANCELED // 已取消
}
}
/*
是订单聚合的根,包含聚合内的所有对象(OrderItem、ShippingAddress);
对外提供addOrderItem、cancelOrder等方法,外部只能通过这些方法操作聚合内对象,无法直接修改orderItems或orderStatus,保证聚合内数据一致性;
自身封装业务规则(如 "仅待支付订单可取消"),体现领域模型的业务价值。
*/
- 领域服务(Domain Service)
- 定义:封装跨实体/跨聚合的业务逻辑,这些逻辑不属于任何单个实体或值对象。
- 核心特征:
- 无状态:不存储数据,只负责执行业务逻辑;
- 业务属性强 :方法名必须使用通用语言,比如
OrderPaymentService.completePayment(); - 只处理领域内的逻辑:不涉及持久化、外部接口调用等技术细节。
- 适用场景:当一个业务操作需要多个实体协作完成时,比如"订单支付"需要修改订单状态、扣减库存、生成支付记录,这些逻辑无法归属到
Order或Inventory单个实体,就需要用领域服务封装。
java
import org.springframework.stereotype.Service;
// 领域服务:处理跨实体/跨聚合的业务逻辑
@Service
public class OrderDomainService {
// 依赖其他聚合的仓储(如库存仓储,此处为演示简化)
private final InventoryRepository inventoryRepository;
public OrderDomainService(InventoryRepository inventoryRepository) {
this.inventoryRepository = inventoryRepository;
}
/**
* 校验订单创建的合法性(跨聚合逻辑:校验商品库存)
*/
public void validateOrderCreation(Order order) {
for (OrderItem orderItem : order.getOrderItems()) {
Long productId = orderItem.getProductId();
Integer requiredQuantity = orderItem.getQuantity();
// 调用库存仓储查询库存
Integer stock = inventoryRepository.getProductStock(productId);
if (stock == null || stock < requiredQuantity) {
throw new IllegalStateException("商品[" + orderItem.getProductName() + "]库存不足,当前库存:" + stock);
}
}
}
}
/*
无状态:仅包含业务逻辑,不存储数据;
处理跨聚合逻辑:订单创建需要校验库存(订单聚合 + 库存聚合),该逻辑无法归属到Order或Inventory单个实体,因此用领域服务封装;
方法名使用通用语言(validateOrderCreation),符合业务语义。
*/
- 仓储(Repository)
- 定义:领域层的抽象接口 ,负责聚合的持久化与查询,屏蔽底层数据存储的细节(如MySQL、MongoDB)。
- 核心作用:
- 让领域层不依赖具体的存储技术,符合依赖倒置原则;
- 确保只有聚合根能被仓储操作,保证聚合的完整性。
- 设计要点:
- 仓储接口 定义在领域层 ,只关注"需要存什么、查什么"(如
OrderRepository.save(Order order)); - 仓储实现类 放在基础设施层,使用ORM框架(如MyBatis、JPA)实现具体的CRUD逻辑;
- 仓储的操作对象是聚合根,而非单个实体或值对象。
- 仓储接口 定义在领域层 ,只关注"需要存什么、查什么"(如
java
import org.springframework.stereotype.Repository;
// 基础设施层:实现领域层的仓储接口
@Repository
public class MyBatisOrderRepository implements OrderRepository {
// 注入MyBatis Mapper(实际项目中需定义OrderMapper)
private final OrderMapper orderMapper;
public MyBatisOrderRepository(OrderMapper orderMapper) {
this.orderMapper = orderMapper;
}
@Override
public void save(Order order) {
// 1. 保存订单主表
orderMapper.insertOrder(order);
// 2. 保存订单项列表(聚合内对象一起持久化)
for (OrderItem orderItem : order.getOrderItems()) {
orderMapper.insertOrderItem(orderItem);
}
}
@Override
public Order findById(Long orderId) {
// 1. 查询订单主信息
Order order = orderMapper.selectOrderById(orderId);
if (order == null) {
return null;
}
// 2. 查询关联的订单项列表(聚合内对象一起查询)
List<OrderItem> orderItems = orderMapper.selectOrderItemsByOrderId(orderId);
order.setOrderItems(orderItems);
return order;
}
@Override
public List<Order> findPendingPaymentOrdersByUserId(Long userId) {
return orderMapper.selectPendingPaymentOrdersByUserId(userId);
}
}
/*
实现领域层OrderRepository接口,依赖OrderMapper(MyBatis 映射器)操作数据库;
保存 / 查询时,同时处理订单主表和订单项表,保证聚合的完整性(符合 "聚合是持久化最小单元" 的规则);
领域层无需关注数据库操作细节,只需调用OrderRepository接口即可。
*/
- 领域事件(Domain Event)
- 定义:领域中发生的重要业务事件 ,用于解耦聚合之间的依赖,实现领域内的异步通信。
- 核心作用:当一个聚合的状态发生变化时,发布领域事件,其他聚合或外部系统订阅并处理该事件,无需直接调用。
- 举例:订单支付成功后,发布
OrderPaidEvent事件,库存子领域订阅该事件扣减库存,物流子领域订阅该事件创建物流单。 - 优势:避免聚合之间的强依赖,提升系统的可扩展性。

三、DDD的分层架构概念
DDD 推荐采用分层架构 组织代码,核心目标是隔离领域逻辑,让领域层成为整个系统的核心,不依赖任何外部层。标准分层从内到外依次为:
| 分层 | 核心职责 | 依赖关系 | 关键组件 |
|---|---|---|---|
| 领域层(Domain Layer) | 封装核心业务规则、领域模型(实体、值对象、聚合根)、领域服务、仓储接口、领域事件 | 不依赖任何外层 | Entity、Value Object、Aggregate Root、Domain Service、Repository(接口)、Domain Event |
| 应用层(Application Layer) | 编排业务流程,协调领域对象完成用户用例,不包含核心业务规则 | 依赖领域层 | Application Service(如OrderApplicationService) |
| 基础设施层(Infrastructure Layer) | 提供技术支撑,实现仓储接口、处理持久化、缓存、消息队列、外部接口调用 | 依赖领域层+应用层 | Repository(实现类)、ORM框架、Redis、MQ、HttpClient工具 |
| 用户接口层(User Interface Layer) | 处理用户请求与响应,如API接口、前端页面、CLI | 依赖应用层 | Controller、DTO(数据传输对象)、VO(视图对象) |
分层核心原则
- 依赖倒置 :内层不依赖外层,外层依赖内层的抽象。比如领域层定义
UserRepository接口,基础设施层实现该接口,领域层无需知道底层是MySQL还是MongoDB。 - 领域层独立:领域层只关注"业务是什么",不关注"怎么存储""怎么调用外部接口",确保业务逻辑不被技术细节污染。
四、DDD与微服务的关系
DDD 与微服务是互补关系,而非绑定关系:
- DDD是微服务拆分的重要指导思想 :子领域是微服务拆分的天然边界------通常一个核心子领域对应一个微服务,支撑子领域和通用子领域可根据情况合并或独立为微服务,避免微服务拆分过细或过粗。
- 微服务是DDD的落地载体:微服务的边界与子领域边界一致,能更好地隔离领域逻辑,实现独立部署和迭代。
- 注意:DDD 也可用于单体应用,比如复杂单体的内部模块划分,并非只能用于微服务。
3. 实践(以后再写,先给出一个结构)
java
order-service/src/main/java/com/example/ddd/order/
├── OrderServiceApplication.java(启动类)
├── config/
│ ├── RedisConfig.java(Redis序列化配置)
│ └── FeignConfig.java(OpenFeign配置)
├── api/(接口层)
│ ├── controller/
│ │ └── OrderController.java
│ └── dto/
│ ├── request/
│ │ ├── OrderCreateRequest.java
│ │ └── OrderCancelRequest.java
│ └── response/
│ └── OrderResponse.java
├── application/(应用层)
│ ├── feign/
│ │ └── UserServiceFeignClient.java(远程调用用户服务)
│ └── service/
│ └── OrderApplicationService.java
├── domain/(领域层)
│ ├── model/
│ │ ├── entity/
│ │ │ ├── Order.java(聚合根)
│ │ │ └── OrderItem.java(实体)
│ │ └── valueobject/
│ │ └── ShippingAddress.java(值对象)
│ ├── repository/
│ │ └── OrderRepository.java(仓储接口)
│ └── service/
│ └── OrderDomainService.java(领域服务)
└── infrastructure/(基础设施层)
├── cache/
│ └── OrderCacheService.java(缓存服务)
└── repository/
└── JpaOrderRepository.java(仓储实现)
java
./ddd-application // 应用层
├── pom.xml
└── src
└── main
└── java
└── com
└── ddd
└── applicaiton
├── converter
│ └── UserApplicationConverter.java // 类型转换器
└── impl
└── AuthrizeApplicationServiceImpl.java // 业务逻辑
./ddd-common
├── ddd-common // 通用类库
│ ├── pom.xml
│ └── src
│ └── main
│ └── java
│ └── com
│ └── ddd
│ └── common
│ ├── exception // 异常
│ │ ├── ServiceException.java
│ │ └── ValidationException.java
│ ├── result // 返回结果集
│ │ ├── BaseResult.javar
│ │ ├── Page.java
│ │ ├── PageResult.java
│ │ └── Result.java
│ └── util // 通用工具
│ ├── GsonUtil.java
│ └── ValidationUtil.java
├── ddd-common-application // 业务层通用模块
│ ├── pom.xml
│ └── src
│ └── main
│ └── java
│ └── com
│ └── ddd
│ └── applicaiton
│ ├── dto // DTO
│ │ ├── RoleInfoDTO.java
│ │ └── UserRoleDTO.java
│ └── servic // 业务接口
│ └── AuthrizeApplicationService.java
├── ddd-common-domain
│ ├── pom.xml
│ └── src
│ └── main
│ └── java
│ └── com
│ └── ddd
│ └── domain
│ ├── event // 领域事件
│ │ ├── BaseDomainEvent.java
│ │ └── DomainEventPublisher.java
│ └── service // 领域接口
│ └── AuthorizeDomainService.java
└── ddd-common-infra
├── pom.xml
└── src
└── main
└── java
└── com
└── ddd
└── infra
├── domain // DO
│ └── AuthorizeDO.java
├── dto
│ ├── AddressDTO.java
│ ├── RoleDTO.java
│ ├── UnitDTO.java
│ └── UserRoleDTO.java
└── repository
├── UserRepository.java // 领域仓库
└── mybatis
└── entity // PO
├── BaseUuidEntity.java
├── RolePO.java
├── UserPO.java
└── UserRolePO.java
./ddd-domian // 领域层
├── pom.xml
└── src
└── main
└── java
└── com
└── ddd
└── domain
├── event // 领域事件
│ ├── DomainEventPublisherImpl.java
│ ├── UserCreateEvent.java
│ ├── UserDeleteEvent.java
│ └── UserUpdateEvent.java
└── impl // 领域逻辑
└── AuthorizeDomainServiceImpl.java
./ddd-infra // 基础服务层
├── pom.xml
└── src
└── main
└── java
└── com
└── ddd
└── infra
├── config
│ └── InfraCoreConfig.java // 扫描Mapper文件
└── repository
├── converter
│ └── UserConverter.java // 类型转换器
├── impl
│ └── UserRepositoryImpl.java
└── mapper
├── RoleMapper.java
├── UserMapper.java
└── UserRoleMapper.java
./ddd-interface
├── ddd-api // 用户接口层
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── ddd
│ │ └── api
│ │ ├── DDDFrameworkApiApplication.java // 启动入口
│ │ ├── converter
│ │ │ └── AuthorizeConverter.java // 类型转换器
│ │ ├── model
│ │ │ ├── req // 入参 req
│ │ │ │ ├── AuthorizeCreateReq.java
│ │ │ │ └── AuthorizeUpdateReq.java
│ │ │ └── vo // 输出 VO
│ │ │ └── UserAuthorizeVO.java
│ │ └── web // API
│ │ └── AuthorizeController.java
│ └── resources // 系统配置
│ ├── application.yml
│ └── resources // Sql文件
│ └── init.sql
└── ddd-task
└── pom.xml
./pom.xml
第二个给出的是**「按分层横向拆分」,第一个提供的是「按业务域(限界上下文)纵向拆分」**,两种拆分各有适用场景
4. 对比
4.1 DDD 与主流框架/架构的详细对比
4.1.1 DDD vs MVC 架构
MVC 是最经典的「界面层架构模式」,核心解决「界面展示与业务逻辑的分离」问题,二者对比如下:
| 对比维度 | DDD(领域驱动设计) | MVC(模型-视图-控制器) |
|---|---|---|
| 设计理念 | 以「业务领域」为核心,聚焦复杂业务规则建模 | 以「界面交互」为核心,聚焦视图与逻辑的分离 |
| 核心目标 | 解决复杂业务的理解、抽象与落地,降低业务与代码的鸿沟 | 解决界面代码与业务代码的耦合,提高界面迭代效率 |
| 核心组件 | 限界上下文、聚合根、领域服务、值对象、仓储、领域事件 | Model(数据/业务模型)、View(视图)、Controller(控制器) |
| 分层结构 | 接口层 → 应用层 → 领域层 → 基础设施层(四层架构,领域层是核心) | 控制器层 → 业务逻辑层(Model) → 视图层(三层架构,Model 是核心) |
| 业务适配性 | 适配复杂业务(如电商、金融、政务),业务规则多变且复杂 | 适配简单/中等业务(如官网、管理后台),业务规则相对固定 |
| 依赖关系 | 领域层不依赖任何外层(基础设施层反向依赖领域层),符合「依赖倒置原则」 | Model 依赖数据层,Controller 依赖 Model,是自上而下的正向依赖 |
| 关联关系 | DDD 可兼容 MVC:MVC 的「Controller」对应 DDD 的「接口层」,MVC 的「Model」可拆分为 DDD 的「应用层+领域层」 | MVC 是 DDD 的「界面层子集」,无法覆盖复杂业务的建模需求 |
举例:
- 简单管理后台(如用户信息CRUD):用 MVC 即可满足,Controller 接收请求,Model 处理简单逻辑,View 展示页面,高效快捷;
- 电商订单系统(如订单创建包含「库存校验、价格计算、优惠券抵扣、风控审核」等复杂规则):用 DDD 建模,将这些规则封装在「订单领域服务」中,MVC 的 Controller 仅作为接口入口,不包含业务逻辑。
4.1.2 DDD vs 传统分层架构(三层架构)
传统分层架构(表现层 → 业务逻辑层 → 数据访问层)是 MVC 的延伸,更侧重「技术职责拆分」,二者对比如下:
| 对比维度 | DDD(领域驱动设计) | 传统分层架构(表现层→业务逻辑层→数据访问层) |
|---|---|---|
| 设计理念 | 「业务导向」:按业务领域拆分,强调业务语义的抽象 | 「技术导向」:按技术职责拆分,强调技术功能的分离 |
| 核心目标 | 让代码「反映业务本质」,便于业务人员与技术人员沟通 | 让代码「职责清晰」,便于技术人员维护(如数据访问层统一操作数据库) |
| 分层核心 | 领域层(封装业务规则,无技术依赖,可独立演进) | 业务逻辑层(混合业务规则与技术逻辑,耦合度高) |
| 业务逻辑归属 | 纯业务规则在「领域服务/聚合根」中,流程编排在「应用服务」中,技术实现在「基础设施层」 | 所有业务逻辑+部分技术逻辑(如事务、缓存)都堆积在「业务逻辑层」 |
| 可维护性 | 业务变更仅需修改领域层,外层无需改动,可维护性高 | 业务变更需修改业务逻辑层,可能牵连表现层和数据访问层,维护成本随业务复杂度上升而激增 |
| 适用场景 | 复杂业务系统(如金融核心系统、电商交易系统) | 简单业务系统(如内部工具、小型管理系统) |
关键差异 :
传统分层架构的「业务逻辑层」是「技术视角的混合体」,而 DDD 的「领域层」是「业务视角的纯净体」------比如「订单价格计算」,传统分层会直接写在业务逻辑层;DDD 会将价格计算的规则(如「商品单价×数量-优惠券金额+运费」)封装在「订单聚合根」的calculateTotalPrice()方法中,属于纯业务逻辑,不包含任何技术代码(如数据库操作、缓存操作)。
4.1.3 DDD vs Clean Architecture(整洁架构)
Clean Architecture(整洁架构,又称「洋葱架构」)是一种「依赖倒置」的架构思想,与 DDD 高度契合,二者对比如下:
| 对比维度 | DDD(领域驱动设计) | Clean Architecture(整洁架构) |
|---|---|---|
| 设计理念 | 以「业务领域」为核心,聚焦业务建模与业务规则落地 | 以「核心逻辑」为核心,聚焦依赖关系与代码隔离,强调「内层不依赖外层」 |
| 核心目标 | 解决复杂业务的建模问题,降低业务与代码的鸿沟 | 解决代码的耦合问题,提高代码的可维护性、可测试性 |
| 核心结构 | 四层架构(接口层→应用层→领域层→基础设施层),领域层是核心 | 同心圆架构(核心层→应用层→接口适配层→外部层),核心层(业务规则)是核心 |
| 组件对应关系 | DDD 领域层 = 整洁架构核心层;DDD 应用层 = 整洁架构应用层;DDD 基础设施层 = 整洁架构接口适配层;DDD 接口层 = 整洁架构外部层 | 整洁架构是 DDD 的「架构骨架」,DDD 是整洁架构的「业务填充」 |
| 侧重点 | 侧重「业务抽象」:定义限界上下文、聚合根等业务概念 | 侧重「依赖规范」:定义「内层不依赖外层,所有依赖向内指向」的规则 |
| 关联关系 | 二者高度兼容,DDD 是整洁架构在「业务领域」的具体落地,整洁架构是 DDD 的「架构保障」 | 整洁架构可脱离 DDD 存在(如用于非业务系统),但业务系统中,整洁架构常与 DDD 结合使用 |
举例:
- DDD 的「领域服务」对应整洁架构的「核心层」,仅包含业务规则,不依赖任何外部技术;
- DDD 的「仓储接口」定义在领域层,「仓储实现」放在基础设施层,符合整洁架构「内层定义接口,外层实现接口」的依赖倒置原则;
- DDD 的「接口层(Controller)」对应整洁架构的「外部层」,负责接收外部请求,依赖应用层,不影响核心业务逻辑。
4.1.4 DDD vs 微服务架构
微服务架构是一种「系统部署与拆分的架构风格」,DDD 是微服务拆分的「核心指导思想」,二者对比如下:
| 对比维度 | DDD(领域驱动设计) | 微服务架构 |
|---|---|---|
| 设计理念 | 以「业务领域」为核心,提供业务层面的拆分依据 | 以「独立部署、独立扩容」为核心,提供技术层面的部署方案 |
| 核心目标 | 解决「业务拆分不合理」导致的微服务耦合问题 | 解决「单体应用」的可扩展性、可维护性问题 |
| 核心产出 | 限界上下文(微服务拆分的最小单位) | 独立的微服务应用(可单独部署、升级、扩容) |
| 拆分依据 | 按业务边界拆分(限界上下文),确保微服务内高内聚、微服务间低耦合 | 按技术/团队/业务粒度拆分(早期常无明确依据,易出现「微服务拆分过细/过粗」问题) |
| 依赖关系 | 限界上下文之间通过「领域事件/公共API」通信,无直接依赖 | 微服务之间通过「HTTP/消息队列」通信,需解决服务注册、熔断、降级等问题 |
| 关联关系 | DDD 是微服务拆分的「方法论指导」,没有 DDD 的微服务易陷入「分布式单体」困境 | 微服务是 DDD 的「部署载体」,DDD 的限界上下文可落地为独立微服务 |
关键差异与关联:
- 没有 DDD 指导的微服务:可能按技术模块拆分(如「用户微服务」包含用户管理、权限管理、消息推送等不相关业务),导致微服务内耦合度高,微服务间依赖复杂,成为「分布式单体」;
- 有 DDD 指导的微服务:按「限界上下文」拆分(如「用户限界上下文」对应「用户微服务」,「订单限界上下文」对应「订单微服务」),每个微服务内业务高度内聚,微服务间通过明确的 API 通信,真正实现「高内聚、低耦合」。
4.1.5 DDD vs 传统技术框架(Spring Boot/MyBatis)
传统技术框架是「落地工具」,DDD 是「设计思想」,二者并非竞争关系,而是「互补关系」,对比如下:
| 对比维度 | DDD(领域驱动设计) | 传统技术框架(Spring Boot/MyBatis) |
|---|---|---|
| 本质属性 | 业务架构设计方法论(无具体技术实现) | 技术实现框架(提供具体的技术功能) |
| 核心作用 | 指导「如何设计代码结构」,让代码贴合业务 | 解决「如何快速实现功能」,提高开发效率 |
| 依赖关系 | DDD 不依赖任何技术框架,可基于任意语言/框架落地(如 Java/Spring Boot、Go/Gin) | 技术框架是 DDD 的「落地载体」,DDD 的分层架构常通过 Spring Boot 实现(如 @Service 注解标记应用服务/领域服务) |
| 覆盖范围 | 覆盖「业务建模→代码设计→系统拆分」全流程 | 覆盖「功能实现→技术集成→部署运行」全流程 |
| 关联关系 | 二者是「思想与工具」的关系:DDD 负责「做什么」(业务设计),技术框架负责「怎么做」(技术实现) | 技术框架可脱离 DDD 单独使用(如简单 CRUD 项目),但复杂业务项目中,DDD 需结合技术框架落地 |
举例:
- DDD 的「仓储接口」:定义在领域层,描述「需要获取用户信息」的业务需求;
- MyBatis:在基础设施层实现仓储接口,提供「通过 SQL 查询用户信息」的技术实现;
- Spring Boot:提供依赖注入、事务管理等能力,将 DDD 的各层组件(应用服务、领域服务、仓储实现)组装起来,形成可运行的系统。
4.2 各类框架/架构的适用场景总结
| 框架/架构类型 | 核心优势 | 适用场景 | 不适用场景 |
|---|---|---|---|
| DDD | 贴合复杂业务、降低业务与代码鸿沟、便于微服务拆分 | 复杂业务系统(电商、金融、政务、医疗) | 简单业务系统(小型工具、静态官网) |
| MVC | 界面与逻辑分离、开发高效、上手简单 | 简单/中等业务的界面系统(管理后台、官网) | 无界面的复杂业务系统(如后端服务) |
| 传统分层架构 | 技术职责清晰、上手简单、开发成本低 | 简单业务系统(内部工具、小型管理系统) | 复杂业务系统(业务规则多变、耦合度高) |
| Clean Architecture | 依赖隔离、可维护性高、可测试性强 | 对代码质量要求高的中大型系统 | 小型快速迭代项目(成本过高) |
| 微服务架构 | 独立部署、独立扩容、团队并行开发 | 大型分布式系统(用户量高、业务复杂) | 小型项目(部署成本高、运维复杂) |
| Spring Boot/MyBatis | 快速开发、技术生态完善、集成便捷 | 所有 Java 后端项目(作为落地工具) | 非 Java 技术栈项目(如 Go、Python 项目) |
5. 总结
本文围绕DDD领域驱动设计展开全面解析,从核心思想到实践落地,再到与主流框架/架构的对比,清晰呈现了DDD的价值与适用边界,核心总结如下:
- DDD的核心定位是**「业务导向的设计方法论」**,而非可直接复用的技术框架。它以"领域"为核心,通过通用语言消除业务与技术的沟通壁垒,借助实体、值对象、聚合根、领域服务等核心概念将复杂业务规则转化为代码模型,最终实现"业务模型与代码模型的一致性"。其核心价值在于解决复杂业务系统的建模与维护问题,避免业务逻辑与技术细节耦合,支撑系统的高速迭代与团队高效协作。
- DDD的实践落地具有灵活的结构选型。 文档提供了两种核心代码组织方式:一是「按业务域(限界上下文)纵向拆分」,适合微服务架构,每个业务域包含完整的接口层、应用层、领域层、基础设施层,实现业务独立部署与迭代;二是「按分层横向拆分」,适合单体或集中式项目,将所有业务的同一层代码聚合到统一模块,提升技术复用性。两种方式均遵循"领域层为核心、依赖倒置"的分层原则,确保领域逻辑的独立性与纯净性。
- DDD与其他框架/架构是「互补而非竞争关系」,选择的核心是匹配业务复杂度。与MVC、传统分层架构相比,DDD更适配复杂业务(如电商、金融),而后者适合简单业务场景(如管理后台、内部工具);与Clean Architecture(整洁架构)相比,二者高度契合,整洁架构提供"内层不依赖外层"的架构骨架,DDD则填充业务逻辑,共同打造高可维护性系统;与微服务架构相比,DDD是微服务拆分的核心指导思想(限界上下文为拆分边界),微服务则是DDD的落地载体,避免陷入"分布式单体"困境;与Spring Boot/MyBatis等技术框架相比,DDD负责"业务设计(做什么)",技术框架负责"技术实现(怎么做)",二者结合实现业务与技术的高效落地。
- DDD的应用需理性评估场景。对于业务规则复杂、需长期迭代、团队协作要求高的系统(如金融核心系统、电商交易系统) ,DDD能显著提升系统可维护性与业务适配性;对于简单CRUD、快速验证需求的小型项目,过度使用DDD会增加设计成本,选择MVC或传统分层架构更高效。