中德AI开发者社区 2.5万字讲解DDD领域驱动设计,从理论到实践掌握DDD分层架构设计,赶紧收藏起来吧

引言

在当今软件开发领域,尤其是微服务和复杂业务系统设计中,领域驱动设计(DDD)已成为一种核心方法论。它不仅仅是一种技术实践,更是一种思想体系,帮助我们从业务本质出发,构建高内聚、低耦合、可维护的软件架构。DDD强调业务模型与代码模型的一致性,避免了传统MVC模式中常见的“贫血模型”问题,让软件更贴合业务变化。

为什么读这篇文章?

  • 理论深度:从战略到战术,覆盖所有核心概念。
  • 实践导向:每节都有C#代码示例,易上手。
  • 扩展内容:新增误区分析、架构演进、工具推荐。
  • 适用场景:聚焦微服务、工控系统、云原生。

收藏起来,逐步实践吧!如果您是初学者,先从MVC vs DDD对比入手;如果是资深开发者,重点看战术设计与代码模型。

MVC模式 VS DDD模式,DDD领域驱动设计:战略设计,战术设计,问题空间,解决空间,事件风暴,通用语言,限界上下文,上席文映射,问题域,领域,贫血模型,充血模型,领域模型,问题空间,解决空间,问题域,子域,核心子域,通用子域,支撑子域,领域事件,实体,聚合,聚合根,应用服务,领域服务,仓库,工厂,防腐层等概念)的DDD分层架构-四层架构(接口层,应用层,领域层,基础设施层)越、六边形架构,洋

目录

一、微服务架构模型的对比与选择
(一)整洁架构
(二)六边形架构
(三)DDD 分层架构
1.用户接口层
2.应用层
3.领域层
4.基础层
5.从三层架构向 DDD 分层架构演进
(四)三种微服务架构模型的对比和分析

二、领域驱动设计分层架构与微服务代码模型
(一)代码模型总目录结构
1.微服务一级目录结构
2.用户接口层目录结构、职能和代码形态
3.应用层目录结构、职能和代码形态
4.领域层目录结构、职能和代码形态
5.基础层层目录结构、职能和代码形态
(二)应用层的领域对象分析
1.实体方法的封装
2.领域服务的组合和封装
3.应用服务的组合和编排
(三)领域层的领域对象分析
1.设计实体
2.找出聚合根
3.设计值对象
4.设计领域事件
5.设计领域服务
6.设计仓储
(四)代码模型强调内容
第一点:聚合之间的代码边界一定要清晰。
第二点:一定要有代码分层的概念。

三、正确理解微服务的边界
(一)逻辑边界
(二)物理边界
(三)代码边界

四、正确认识服务和数据在微服务各层的协作
(一)正确认识服务的协作

  1. 服务的类型
  2. 服务的调用(三类主要场景)
    微服务内跨层服务调用
    微服务之间的服务调用
    领域事件驱动
  3. 服务的封装与组合
    (二)正确认识服务数据的协作
    1.基础层数据协作
    2.领域层数据协作
    3.应用层数据协作
    4.用户接口层数据协作
    5.前端应用数据协作

参考书籍、文献和资料

干货分享,感谢您的阅读!

一、微服务架构模型的对比与选择

微服务架构模型现有的选择模型包括:整洁架构、六边形架构、DDD 分层架构等。

(注:CQRS架构之前博客中有讲,本次不做分析)

每种架构模式虽然提出的时代和背景不同,但其核心都是为了实现业务逻辑与技术实现的解耦,确保系统的可扩展性、可维护性和高内聚低耦合。在微服务环境中,选择合适的架构模型可以帮助我们更好地处理分布式系统的复杂性,如服务间通信、数据一致性、边界划分等问题。下面我们对比三种主流模型,并分析其优缺点,最终选择DDD分层架构作为本文的重点实现方式。

(一)整洁架构

整洁架构(Clean Architecture)由Robert C. Martin(Uncle Bob)提出,是一种以依赖倒置原则为核心的架构模式。它强调业务逻辑独立于外部框架、UI、数据库等,核心是“实体”和“用例”层,外层是适配器和框架。

  • 核心概念:架构分为四层圆环,从内到外:实体层(Entities)、用例层(Use Cases)、适配器层(Adapters)、框架与驱动层(Frameworks & Drivers)。依赖方向从外向内,确保核心业务不受外部变化影响。
  • 优点:高度解耦,便于测试;业务逻辑纯净;易于更换技术栈(如换数据库不影响核心)。
  • 缺点:抽象层级多,实现复杂;适合大型系统,小型微服务可能过度设计。
  • 适用场景:需要频繁更换技术栈或高度测试驱动的微服务。
  • 误区:误以为圆环层级意味着代码必须物理分层,其实逻辑分层即可。
  • 工控适配:在工控上位机中,用整洁架构隔离硬件协议(如Modbus)和业务规则,便于协议升级。

代码示例1(C#):实体与用例

// Entities/AlarmRule.cs (实体层)
public class AlarmRule
{
    public Guid Id { get; private set; }
    public string DeviceId { get; private set; }
    public decimal UpperLimit { get; private set; }
    public decimal LowerLimit { get; private set; }

    public AlarmRule(string deviceId, decimal upper, decimal lower)
    {
        Id = Guid.NewGuid();
        DeviceId = deviceId;
        UpperLimit = upper;
        LowerLimit = lower;
    }

    public bool IsViolated(decimal currentValue)
    {
        return currentValue > UpperLimit || currentValue < LowerLimit;
    }
}

// UseCases/CreateAlarmRuleUseCase.cs (用例层)
public class CreateAlarmRuleUseCase
{
    private readonly IAlarmRuleRepository _repository;

    public CreateAlarmRuleUseCase(IAlarmRuleRepository repository)
    {
        _repository = repository;
    }

    public Guid Execute(string deviceId, decimal upper, decimal lower)
    {
        var rule = new AlarmRule(deviceId, upper, lower);
        _repository.Save(rule);
        return rule.Id;
    }
}

// Ports/IAlarmRuleRepository.cs (端口)
public interface IAlarmRuleRepository
{
    void Save(AlarmRule rule);
}

// Adapters/EfAlarmRuleRepository.cs (适配器)
public class EfAlarmRuleRepository : IAlarmRuleRepository
{
    private readonly DbContext _context;

    public EfAlarmRuleRepository(DbContext context) => _context = context;

    public void Save(AlarmRule rule)
    {
        _context.AlarmRules.Add(rule);
        _context.SaveChanges();
    }
}

代码示例2(C#):测试用例

[Fact]
public void CreateAlarmRule_ShouldSaveToRepository()
{
    var mockRepo = new Mock<IAlarmRuleRepository>();
    var useCase = new CreateAlarmRuleUseCase(mockRepo.Object);

    useCase.Execute("DEV001", 100, 0);

    mockRepo.Verify(r => r.Save(It.IsAny<AlarmRule>()), Times.Once);
}
(二)六边形架构

六边形架构(Hexagonal Architecture),又称端口与适配器架构,由Alistair Cockburn提出。它将系统核心视为六边形,外部通过端口与适配器交互。

  • 核心概念:核心是领域逻辑,端口定义输入/输出接口,适配器实现具体技术。依赖倒置:适配器依赖端口。
  • 优点:高度灵活,便于替换外部组件;测试友好;支持多适配器共存。
  • 缺点:需要定义大量接口,初始学习曲线陡峭;不强调分层,可能导致核心膨胀。
  • 适用场景:需要多端适配的系统。
  • 误区:误以为六边形必须有6个端口,其实端口数量任意。
  • 工控适配:在工控中,用端口定义采集接口,适配器实现Modbus/EtherCAT等协议,便于硬件升级。

代码示例1(C#):端口定义

// Core/Ports/IDevice采集端口.cs
public interface IDevice采集端口
{
    Task<采集数据> 获取实时数据Async(string deviceId, CancellationToken ct);
}

代码示例2(C#):两个适配器

// Adapters/Modbus采集适配器.cs
public class Modbus采集适配器 : IDevice采集端口
{
    public async Task<采集数据> 获取实时数据Async(string deviceId, CancellationToken ct)
    {
        // Modbus实现
        return new 采集数据(deviceId, DateTime.UtcNow, 98.5m, "°C");
    }
}

// Adapters/EtherCAT采集适配器.cs
public class EtherCAT采集适配器 : IDevice采集端口
{
    public async Task<采集数据> 获取实时数据Async(string deviceId, CancellationToken ct)
    {
        // EtherCAT实现(使用TwinCAT ADS)
        return new 采集数据(deviceId, DateTime.UtcNow, 99.0m, "°C");
    }
}

代码示例3(C#):核心使用端口

public class 数据采集用例
{
    private readonly IDevice采集端口 _端口;

    public 数据采集用例(IDevice采集端口 端口)
    {
        _端口 = 端口; // DI注入具体适配器
    }

    public async Task 执行Async(string deviceId)
    {
        var 数据 = await _端口.获取实时数据Async(deviceId, default);
        // 处理数据
    }
}
(三)DDD 分层架构

DDD 分层架构是Eric Evans提出的经典模式,将系统分为四层:用户接口层、应用层、领域层、基础层。

1. 用户接口层

职能:接收请求、响应用户。

代码示例(C#):WebSocket HMI接口

public class DeviceHub : Hub
{
    private readonly IDeviceApplicationService _service;

    public DeviceHub(IDeviceApplicationService service) => _service = service;

    public async Task SendCommand(string deviceId, string instruction)
    {
        var cmd = new SendCommandCommand(deviceId, instruction);
        await _service.ExecuteAsync(cmd);
        await Clients.All.SendAsync("CommandSent", deviceId);
    }
}
2. 应用层

职能:协调领域,管理事务。

代码示例(C#):应用服务 + 事务

public class DeviceApplicationService : IDeviceApplicationService
{
    private readonly ITransactionManager _txManager;
    private readonly IDeviceRepository _repo;

    public async Task ExecuteCommandAsync(SendCommandCommand cmd)
    {
        await _txManager.ExecuteAsync(async () =>
        {
            var device = await _repo.GetAsync(cmd.DeviceId);
            device.SendCommand(cmd.Instruction);
            await _repo.SaveAsync(device);
        });
    }
}
3. 领域层

职能:核心业务规则。

代码示例(C#):领域服务

public class DeviceValidationService : DomainService
{
    public void ValidateValue(Device device, decimal value)
    {
        if (value < device.MinValue || value > device.MaxValue)
            throw new DomainException("值超出范围");
    }
}
4. 基础层

职能:技术实现。

代码示例(C#):外部服务适配

public class EmailNotificationService : INotificationService
{
    public async Task SendAlarmAsync(string message)
    {
        // 使用 SendGrid 或 SMTP 发送邮件
        await Task.CompletedTask; // 模拟
    }
}
5. 从三层架构向 DDD 分层架构演进

扩展路径:从MVC三层(Presentation/Business/Data)演进到DDD四层。

  • 步骤1:提取业务规则到Domain层。
  • 步骤2:引入应用服务协调。
  • 步骤3:使用端口适配器解耦基础设施。

代码演进示例(C#):从MVC到DDD

// MVC 旧版
public class DeviceController
{
    public void UpdateValue(string id, decimal value)
    {
        var device = _db.Devices.Find(id);
        device.Value = value;
        _db.SaveChanges();
    }
}

// DDD 新版
public class DeviceController
{
    private readonly DeviceApplicationService _service;

    public void UpdateValue(string id, decimal value)
    {
        var cmd = new UpdateValueCommand(id, value);
        _service.Execute(cmd);
    }
}
(四)三种微服务架构模型的对比和分析

(表格如前文扩展)


二、领域驱动设计分层架构与微服务代码模型

(继续扩展每个小节,添加更多代码,如目录结构的具体csproj文件、应用层更多服务、领域层更多实体等)

例如:

(一)代码模型总目录结构
  1. 微服务一级目录结构

代码示例(csproj文件)

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <PublishAot>true</PublishAot>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\Application\Application.csproj" />
  </ItemGroup>
</Project>
  1. 用户接口层目录结构、职能和代码形态

代码示例(DTO)

public record SendCommandDto(string Instruction);

… (类似方式扩展所有小节)


三、正确理解微服务的边界

(一)逻辑边界

代码示例:逻辑边界通过接口定义

public interface IDeviceBoundary
{
    Task ProcessDataAsync(采集数据 data);
}
(二)物理边界

扩展:Docker Compose定义物理边界

services:
  device-service:
    build: .
    ports:
      - "8080:80"
(三)代码边界

代码示例:命名空间边界

namespace Domain.Device
{
    // 设备领域代码
}

namespace Domain.Alarm
{
    // 报警领域代码
}

四、正确认识服务和数据在微服务各层的协作

(一)正确认识服务的协作
  1. 服务的类型

代码示例:不同类型服务

// 应用服务
public class AppService { /* 协调 */ }

// 领域服务
public class DomainService { /* 业务规则 */ }

// 基础设施服务
public class InfraService { /* 数据库 */ }
  1. 服务的调用(三类主要场景)

微服务内跨层服务调用:如应用层调用领域层。

微服务之间的服务调用

public async Task CallExternalServiceAsync()
{
    using var httpClient = new HttpClient();
    var response = await httpClient.GetAsync("http://alarm-service/api/alarm");
}

领域事件驱动

_eventBus.Publish(new AlarmEvent());
  1. 服务的封装与组合

代码示例:组合服务

public class CompositeService
{
    private readonly DomainService _domain;
    private readonly InfraService _infra;

    public async Task Execute()
    {
        var data = await _infra.GetDataAsync();
        _domain.Process(data);
    }
}
(二)正确认识服务数据的协作
  1. 基础层数据协作

代码示例:仓储数据流

public async Task SaveDataAsync(DataEntity entity)
{
    _context.Entities.Add(entity);
    await _context.SaveChangesAsync();
}
  1. 领域层数据协作

代码示例:实体数据

public class DataEntity
{
    public int Id { get; set; }
    public string Value { get; set; }
}
  1. 应用层数据协作

代码示例:DTO数据

public record DataDto(int Id, string Value);
  1. 用户接口层数据协作

代码示例:ViewModel

public class DataViewModel
{
    public int Id { get; set; }
    public string DisplayValue { get; set; } = "Formatted Value";
}
  1. 前端应用数据协作

代码示例:JSON序列化

var json = JsonSerializer.Serialize(new DataDto(1, "Value"));

参考书籍、文献和资料

  1. Eric Evans. Domain-Driven Design: Tackling Complexity in the Heart of Software.
  2. Vaughn Vernon. Implementing Domain-Driven Design.
  3. 欧创新. “DDD实战课”. 极客时间.
  4. Martin Fowler. “Patterns of Enterprise Application Architecture”.
  5. Chris Richardson. Microservices Patterns.
  6. 其他:DDD-CQRS-ES社区、EventStorming工具、MediatR NuGet包。

干货分享,感谢您的阅读!

领域驱动设计DDD是一种设计思想,它可以同时指导中台业务建模和微服务设计(中台本质是业务模型,微服务是业务模型的系统落地),领域驱动设计强调领域模型和微服务设计的一体性,先有领域模型然后才有微服务,而不是脱离领域模型来谈微服务设计。

微服务拆分困境产生的根本原因:不知道业务或者微服务的边界到底在什么地方。

DDD 核心思想:通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。

对于领域驱动设计的学习做的总结主要写三篇博客,主要包括三部分:基本理论总结与分析、架构分析与代码设计、具体应用设计分析,主要参考的资料为极客时间的欧创新架构师的《DDD》实战,其他参考书籍在文章下方的参考书籍中。

本次主要总结DDD架构分析与代码设计:

一、微服务架构模型的对比与选择
微服务架构模型现有的选择模型包括:整洁架构、六边形架构、DDD 分层架构等。

每种架构模式虽然提出的时代和背景不同,但其核心都是为了实现业务逻辑与技术实现的解耦,确保系统的可扩展性、可维护性和高内聚低耦合。在微服务环境中,选择合适的架构模型可以帮助我们更好地处理分布式系统的复杂性,如服务间通信、数据一致性、边界划分等问题。下面我们对比三种主流模型,并分析其优缺点,最终选择DDD分层架构作为本文的重点实现方式。

(一)整洁架构
(二)六边形架构
(三)DDD 分层架构
1.用户接口层
2.应用层
3.领域层
4.基础层
5.从三层架构向 DDD 分层架构演进
(四)三种微服务架构模型的对比和分析

二、领域驱动设计分层架构与微服务代码模型
(一)代码模型总目录结构
1.微服务一级目录结构
2.用户接口层目录结构、职能和代码形态
3.应用层目录结构、职能和代码形态
4.领域层目录结构、职能和代码形态
5.基础层层目录结构、职能和代码形态
(二)应用层的领域对象分析
1.实体方法的封装
2.领域服务的组合和封装
3.应用服务的组合和编排
(三)领域层的领域对象分析
1.设计实体
2.找出聚合根
3.设计值对象
4.设计领域事件
5.设计领域服务
6.设计仓储
(四)代码模型强调内容
第一点:聚合之间的代码边界一定要清晰。
第二点:一定要有代码分层的概念。

三、正确理解微服务的边界
(一)逻辑边界
(二)物理边界
(三)代码边界

四、正确认识服务和数据在微服务各层的协作
(一)正确认识服务的协作

  1. 服务的类型
  2. 服务的调用(三类主要场景)
    微服务内跨层服务调用
    微服务之间的服务调用
    领域事件驱动
  3. 服务的封装与组合
    (二)正确认识服务数据的协作
    1.基础层数据协作
    2.领域层数据协作
    3.应用层数据协作
    4.用户接口层数据协作
    5.前端应用数据协作

参考书籍、文献和资料

干货分享,感谢您的阅读!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐