Stay Hungry,Stay Foolish!

Comprehensive Guide to Domain-Driven Design (DDD)

Comprehensive Guide to Domain-Driven Design (DDD)

https://jdaniel1987.github.io/DomainDrivenDesign

 

这是一篇基于你提供的网页内容整理的博客文章。为了便于读者理解,我重新梳理了结构,并对关键代码和概念进行了重点标注。


🚀 全面指南:领域驱动设计 (DDD) 核心与进阶

作者:Jaime Daniel Delgado Ortega
发布日期:2024年9月23日

领域驱动设计(DDD)是一种以业务领域为核心的软件开发战略方法。它通过将软件模型与业务概念对齐,提供了一套管理复杂性的工具。

本文将深入探讨 DDD 的核心概念与进阶模式,并结合 .NET 代码示例,展示如何在项目中应用这些理念。


🧩 DDD 的核心概念

1. 通用语言 (Ubiquitous Language)

通用语言是开发人员和领域专家(如产品经理)之间共享的词汇表。它确保所有参与者对业务概念的理解保持一致。

  • 示例:在代码和业务沟通中,“客户”指代同一对象,“订单状态”的生命周期(待处理、已发货、已送达)在系统中是统一的。

2. 实体 (Entities)

实体是拥有唯一标识(ID)的对象,其身份在生命周期中保持不变。

public class OrderItem 
{
    public required Guid Id { get; set; } // 唯一标识
    public required string ProductName { get; set; }
    public required decimal Price { get; set; }
    public required int Quantity { get; set; }
}

3. 值对象 (Value Objects)

值对象没有唯一标识,它们通过属性值来定义。如果两个值对象的所有属性都相同,则视为相等。值对象通常是不可变的。

代码示例Price 作为一个值对象,通过 record 实现不可变性,并重载了运算符。

public record Price 
{
    public decimal Value { get; init; }

    private Price(decimal value)
    {
        if (value < 0) throw new ArgumentException("Price cannot be negative");
        Value = value;
    }

    public static Price Create(decimal value) => new(value);

    // 重载运算符,支持价格直接相加
    public static Price operator +(Price a, Price b) => new Price(a.Value + b.Value);
}

4. 聚合 (Aggregates)

聚合是一组相关对象的集合,作为一个整体被对待。聚合根(Aggregate Root)负责维护聚合内部的一致性。

public class Order 
{
    public required Guid Id { get; set; }
    public required DateTime OrderDate { get; set; }
    public required Customer Customer { get; set; }
    public required List<OrderItem> Items { get; set; }
}

5. 仓储 (Repositories)

仓储充当聚合根集合的抽象,隔离了领域模型与底层数据访问逻辑。

public interface IOrderRepository 
{
    Task<Order> GetById(int id);
    Task Save(Order order);
}

6. 领域服务 (Domain Services)

当某些领域逻辑不适合放在实体或值对象中时(例如涉及多个聚合的操作),我们将其封装在领域服务中。

public class PaymentService 
{
    public bool ProcessPayment(Order order, PaymentDetails paymentDetails)
    {
        // 处理支付的核心领域逻辑
    }
}

🚀 进阶 DDD 概念

1. 限界上下文 (Bounded Contexts)

限界上下文定义了特定领域模型的边界。同一个概念(如“订单”)在不同的上下文中可能有不同的定义和属性。

  • 销售上下文 (Sales Context):订单包含客户和支付信息。
  • 发货上下文 (Shipping Context):订单仅包含发货地址和追踪号。

2. 领域事件 (Domain Events)

领域事件用于通知系统业务逻辑中发生了重要变化,常用于解耦。

// 定义事件
public record OrderPlacedEvent(int OrderId, DateTime PlacedOn) : IDomainEvent;

// 处理事件
public class OrderPlacedHandler : IEventHandler<OrderPlacedEvent> 
{
    public Task Handle(OrderPlacedEvent domainEvent)
    {
        // 处理订单创建后的逻辑,如发送通知
    }
}

3. 工厂 (Factories)

工厂用于封装复杂聚合的创建逻辑,确保聚合在创建时即满足所有业务规则。

public class OrderFactory 
{
    public static Order CreateOrder(Customer customer, List<OrderItem> items)
    {
        var order = new Order() { CustomerId = customer.Id, /*...*/ };
        foreach (var item in items) order.AddItem(item);
        return order;
    }
}

4. 事件溯源 (Event Sourcing)

事件溯源不直接存储对象的当前状态,而是存储导致状态变化的一系列事件。通过重放事件来重建对象状态。

public class Order 
{
    public OrderStatus Status { get; set; }
    private List<IDomainEvent> _events = new List<IDomainEvent>();

    public void Apply(OrderPlacedEvent @event)
    {
        this.Status = OrderStatus.Placed; // 根据事件更新状态
        _events.Add(@event); // 记录事件
    }
}

5. 防腐层 (Anti-Corruption Layer, ACL)

ACL 用于保护当前领域的模型不受外部系统模型的影响,通过转换层将外部模型翻译为内部领域模型。

public class ExternalCustomerAdapter 
{
    public Customer Convert(ExternalCustomer externalCustomer)
    {
        // 将外部客户模型转换为内部领域客户模型
    }
}

6. 规约 (Specifications)

规约模式将业务规则封装为可重用的对象,用于验证对象或过滤集合。

public class EligibleForDiscountSpecification : ISpecification<Order> 
{
    public bool IsSatisfiedBy(Order order)
    {
        return order.TotalAmount > 100; // 满100元符合折扣条件
    }
}

7. 策略 (Policies)

策略封装了可能影响系统不同部分的复杂业务规则,通常响应领域事件执行。

public class DiscountPolicy 
{
    public decimal ApplyDiscount(Order order)
    {
        if (order.TotalAmount > 500) return order.TotalAmount * 0.10m; // 满500打9折
        return 0;
    }
}

⚖️ DDD 的利与弊

✅ 优势

  • 清晰性:软件设计与业务高度对齐,直观易懂。
  • 可扩展性:通过限界上下文、CQRS 和事件溯源,系统能更好地应对复杂度和性能扩展。
  • 灵活性:更容易适应业务领域的变更。

⚠️ 挑战

  • 学习曲线:概念较多,团队上手难度大。
  • 复杂性:对于简单项目,引入 DDD 可能导致过度设计。

🔗 DDD、整洁架构与 CQRS 的关系

这三者是互补的架构方法:

  1. DDD:专注于业务建模,确保核心逻辑反映真实业务。
  2. 整洁架构:强调关注点分离,将业务逻辑置于中心,独立于框架和数据库。
  3. CQRS:分离读写操作,配合 DDD 的限界上下文,使复杂业务操作的设计更加聚焦。

总结:DDD 提供了一套系统化的方法来管理软件复杂性。虽然它引入了额外的复杂性,但对于大型、复杂的业务系统,其带来的长期可维护性和业务对齐价值是巨大的。


本文基于 Eric Evans 的经典著作《领域驱动设计:软件核心复杂性应对之道》整理。

 

posted @ 2026-08-25 22:52  lightsong  阅读(6)  评论(0)    收藏  举报
千山鸟飞绝,万径人踪灭