一、领域驱动设计与三层架构的本质区别

让我们从一个电商系统的订单处理模块说起。假设我们使用C#技术栈实现:

// 传统三层架构示例
public class OrderService  // 业务逻辑层
{
    private readonly IOrderRepository _repository;
    
    public OrderService(IOrderRepository repository)
    {
        _repository = repository;
    }
    
    public void CreateOrder(OrderDto dto)
    {
        // 数据验证
        if(dto.Items.Count == 0) 
            throw new Exception("订单商品不能为空");
            
        // 数据库操作
        var order = new Order {
            Id = Guid.NewGuid(),
            Items = dto.Items
        };
        _repository.Add(order);
    }
}

// 领域驱动设计示例
public class Order : AggregateRoot  // 领域模型
{
    private List<OrderItem> _items = new();
    
    private Order() {}  // 私有构造函数
    
    public static Order Create(List<OrderItem> items)
    {
        if(items.Count == 0)
            throw new DomainException("订单必须包含商品");
            
        var order = new Order {
            Id = new OrderId(Guid.NewGuid())
        };
        order._items.AddRange(items);
        
        order.AddDomainEvent(new OrderCreatedEvent(order.Id));
        return order;
    }
}

三层架构像是个流水线工人,按部就班地处理数据;而DDD则像个专业顾问,把业务规则内化到模型里。最大的区别在于:

  1. 关注点不同:三层关注技术实现,DDD关注业务语义
  2. 代码组织方式:三层按技术分层,DDD按业务能力划分界限上下文
  3. 业务逻辑位置:三层多在Service层,DDD则在领域模型中

二、架构演进的核心驱动力

为什么我们需要从三层架构演进到更复杂的架构?让我们看个库存管理的例子:

// 传统三层的库存扣减
public class InventoryService
{
    public void ReduceStock(string sku, int quantity)
    {
        var stock = _repository.Get(sku);
        if(stock.Quantity < quantity)
            throw new Exception("库存不足");
            
        stock.Quantity -= quantity;
        _repository.Update(stock);
    }
}

// DDD的库存聚合根
public class Inventory : AggregateRoot
{
    private string _sku;
    private int _quantity;
    private List<StockMovement> _movements;
    
    public void Reduce(int quantity)
    {
        if(_quantity < quantity)
            throw new DomainException($"库存不足,当前{_quantity},需要{quantity}");
            
        _quantity -= quantity;
        _movements.Add(new StockMovement(
            MovementType.Outbound, 
            quantity,
            DateTime.Now));
            
        AddDomainEvent(new StockReducedEvent(_sku, quantity));
    }
}

驱动架构演进的因素主要有:

  1. 业务复杂度:当if-else超过5层时就该考虑DDD了
  2. 团队规模:10人以上的团队需要清晰的上下文边界
  3. 变更频率:高频变更的业务适合用DDD建立稳定模型
  4. 性能需求:CQRS模式可以分离读写负载

三、实战中的架构选择指南

让我们通过用户权限系统对比两种实现。假设使用.NET技术栈:

// 三层架构实现
public class PermissionService
{
    public bool HasPermission(int userId, string permissionCode)
    {
        var userRoles = _userRepository.GetRoles(userId);
        var rolePermissions = _roleRepository.GetPermissions(userRoles);
        return rolePermissions.Contains(permissionCode);
    }
}

// DDD实现
public class User : AggregateRoot
{
    private List<Role> _roles;
    
    public bool HasPermission(Permission permission)
    {
        return _roles.Any(r => r.Permissions
            .Exists(p => p.Equals(permission)));
    }
}

public class Permission : ValueObject
{
    public string Code { get; }
    
    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return Code;
    }
}

选择建议:

  1. 适合三层架构的场景:

    • 简单CRUD应用
    • 短期快速迭代的项目
    • 业务规则简单的内部系统
  2. 适合DDD的场景:

    • 复杂的业务规则(如金融系统)
    • 需要长期演进的核心系统
    • 多团队协作的大型项目

四、架构转型的注意事项

在从三层向DDD演进时,要注意这些坑:

// 错误的DDD实现示例
public class OrderService  // 反模式:贫血模型
{
    public void ValidateOrder(Order order)
    {
        if(order.Items.Count == 0)
            throw new Exception("无效订单");
    }
}

// 正确的DDD做法
public class Order
{
    private List<Item> _items;
    
    public Order(List<Item> items)
    {
        if(items.Count == 0)
            throw new DomainException("订单必须包含商品");
            
        _items = items;
    }
}

关键注意事项:

  1. 不要为了DDD而DDD:适合的才是最好的
  2. 渐进式改造:可以先从核心域开始
  3. 统一语言:建立团队通用的术语表
  4. 技术债务管理:明确架构边界

五、总结与展望

经过上面的对比分析,我们可以得出:

  1. 三层架构就像瑞士军刀,简单实用但功能有限
  2. DDD像专业工具包,针对复杂场景但学习成本高
  3. 现代架构趋势是混合使用:核心域用DDD,支撑子域用三层
  4. 未来可能会涌现更多面向特定场景的架构模式

无论选择哪种架构,记住架构的本质是管理复杂度。好的架构应该像城市交通系统,既要有主干道(核心域),也要有小巷子(简单功能),各司其职又有机统一。