DDD领域驱动设计:核心概念、实践结构与框架对比

目录

  • [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的基础,决定了整个设计方法论的导向。

  1. 领域(Domain)

    • 定义:软件要解决的特定业务问题范围,是业务的边界。
    • 举例:电商领域、金融支付领域、物流仓储领域;一个电商领域又可细分为订单、商品、用户、支付等更小的业务范围。
    • 核心:所有设计都围绕领域内的业务规则展开,而非技术实现。
  2. 通用语言(Ubiquitous Language)

    • 定义:业务人员与技术人员共同认可、统一使用的业务术语体系,贯穿需求分析、设计、编码、测试全流程。
    • 作用:消除"业务说的术语"和"代码中的命名"之间的鸿沟,比如业务说"订单履约",代码中就有OrderFulfillmentService,而非模糊的OrderStatusUpdateService
    • 要求:团队沟通必须使用通用语言,禁止技术人员自创与业务无关的术语。
  3. 子领域(Subdomain)

    • 定义:将大领域拆分为更小的、内聚的业务单元,每个子领域对应一个独立的业务能力。
    • 分类(按业务重要性):
      • 核心子领域 :系统的核心竞争力,如电商的订单交易子领域 、银行的核心账务子领域
      • 支撑子领域 :支持核心业务的辅助能力,如电商的用户认证子领域库存管理子领域
      • 通用子领域 :多个子领域复用的公共能力,如日志子领域权限子领域,可封装为公共组件。

二、DDD的核心领域建模概念

领域建模是DDD的核心,目的是将业务规则转化为可落地的代码模型,核心组件都集中在领域层

  1. 实体(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关联),外部无法直接修改订单项,需通过订单聚合根操作。
*/
  1. 值对象(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,负责属性合法性校验,保证值对象的有效性。
*/
  1. 聚合(Aggregate)与聚合根(Aggregate Root)
    • 聚合一组紧密关联的领域对象的集合 ,作为一个统一的修改单元和数据一致性边界 。比如订单聚合包含Order(订单)、OrderItem(订单项)、ShippingAddress(收货地址)。
    • 聚合根 :聚合的根实体,是聚合对外的唯一访问入口,负责维护聚合内的业务规则和数据一致性。
    • 聚合的核心设计规则 (必须严格遵守):
      1. 外部对象只能通过聚合根访问聚合内的其他对象,不能直接操作聚合内的非根对象(如不能直接修改OrderItem,必须通过Order操作);
      2. 聚合内的对象可以直接关联,聚合之间只能通过聚合根ID关联(避免跨聚合的复杂依赖);
      3. 聚合是数据持久化的最小单元------一次只能保存或修改一个聚合,确保聚合内的数据一致性。
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,保证聚合内数据一致性;
自身封装业务规则(如 "仅待支付订单可取消"),体现领域模型的业务价值。
*/
  1. 领域服务(Domain Service)
    • 定义:封装跨实体/跨聚合的业务逻辑,这些逻辑不属于任何单个实体或值对象。
    • 核心特征:
      • 无状态:不存储数据,只负责执行业务逻辑;
      • 业务属性强 :方法名必须使用通用语言,比如OrderPaymentService.completePayment()
      • 只处理领域内的逻辑:不涉及持久化、外部接口调用等技术细节。
    • 适用场景:当一个业务操作需要多个实体协作完成时,比如"订单支付"需要修改订单状态、扣减库存、生成支付记录,这些逻辑无法归属到OrderInventory单个实体,就需要用领域服务封装。
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),符合业务语义。
*/
  1. 仓储(Repository)
    • 定义:领域层的抽象接口 ,负责聚合的持久化与查询,屏蔽底层数据存储的细节(如MySQL、MongoDB)。
    • 核心作用:
      • 让领域层不依赖具体的存储技术,符合依赖倒置原则
      • 确保只有聚合根能被仓储操作,保证聚合的完整性。
    • 设计要点:
      1. 仓储接口 定义在领域层 ,只关注"需要存什么、查什么"(如OrderRepository.save(Order order));
      2. 仓储实现类 放在基础设施层,使用ORM框架(如MyBatis、JPA)实现具体的CRUD逻辑;
      3. 仓储的操作对象是聚合根,而非单个实体或值对象。
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接口即可。
*/
  1. 领域事件(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 与微服务是互补关系,而非绑定关系:

  1. DDD是微服务拆分的重要指导思想子领域是微服务拆分的天然边界------通常一个核心子领域对应一个微服务,支撑子领域和通用子领域可根据情况合并或独立为微服务,避免微服务拆分过细或过粗。
  2. 微服务是DDD的落地载体:微服务的边界与子领域边界一致,能更好地隔离领域逻辑,实现独立部署和迭代。
  3. 注意: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的价值与适用边界,核心总结如下:​

  1. DDD的核心定位是**「业务导向的设计方法论」**,而非可直接复用的技术框架。它以"领域"为核心,通过通用语言消除业务与技术的沟通壁垒,借助实体、值对象、聚合根、领域服务等核心概念将复杂业务规则转化为代码模型,最终实现"业务模型与代码模型的一致性"。其核心价值在于解决复杂业务系统的建模与维护问题,避免业务逻辑与技术细节耦合,支撑系统的高速迭代与团队高效协作。
  2. DDD的实践落地具有灵活的结构选型。 文档提供了两种核心代码组织方式:一是「按业务域(限界上下文)纵向拆分」,适合微服务架构,每个业务域包含完整的接口层、应用层、领域层、基础设施层,实现业务独立部署与迭代;二是「按分层横向拆分」,适合单体或集中式项目,将所有业务的同一层代码聚合到统一模块,提升技术复用性。两种方式均遵循"领域层为核心、依赖倒置"的分层原则,确保领域逻辑的独立性与纯净性。
  3. DDD与其他框架/架构是「互补而非竞争关系」,选择的核心是匹配业务复杂度。与MVC、传统分层架构相比,DDD更适配复杂业务(如电商、金融),而后者适合简单业务场景(如管理后台、内部工具);与Clean Architecture(整洁架构)相比,二者高度契合,整洁架构提供"内层不依赖外层"的架构骨架,DDD则填充业务逻辑,共同打造高可维护性系统;与微服务架构相比,DDD是微服务拆分的核心指导思想(限界上下文为拆分边界),微服务则是DDD的落地载体,避免陷入"分布式单体"困境;与Spring Boot/MyBatis等技术框架相比,DDD负责"业务设计(做什么)",技术框架负责"技术实现(怎么做)",二者结合实现业务与技术的高效落地。
  4. DDD的应用需理性评估场景。对于业务规则复杂、需长期迭代、团队协作要求高的系统(如金融核心系统、电商交易系统) ,DDD能显著提升系统可维护性与业务适配性;对于简单CRUD、快速验证需求的小型项目,过度使用DDD会增加设计成本,选择MVC或传统分层架构更高效。
相关推荐
何中应2 小时前
Bean的三种注入方式
开发语言·spring boot·后端·spring
ArabySide2 小时前
【Java】重构之善用多态解耦,记录一次模板方法实践
java·重构·模板方法模式
wanghowie2 小时前
01.03 Java基础篇|面向对象核心与设计实践
java·开发语言
vortex52 小时前
ORM是什么?如何理解ORM?ORM的优缺点?
java·数据库·sql·mysql·oracle·orm
Algebraaaaa2 小时前
为什么线程阻塞要用.join而不是.wait
java·c++·python
是苏浙2 小时前
零基础入门Java之设计图书管理系统
java·开发语言
墨雪不会编程2 小时前
C++内存管理深度剖析
java·开发语言·c++
BBB努力学习程序设计2 小时前
Java Scanner完全指南:让程序与用户对话
java
BBB努力学习程序设计2 小时前
Java面向对象编程:封装、继承与多态深度解析
java