一、领域驱动设计与三层架构的本质区别
让我们从一个电商系统的订单处理模块说起。假设我们使用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则像个专业顾问,把业务规则内化到模型里。最大的区别在于:
- 关注点不同:三层关注技术实现,DDD关注业务语义
- 代码组织方式:三层按技术分层,DDD按业务能力划分界限上下文
- 业务逻辑位置:三层多在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));
}
}
驱动架构演进的因素主要有:
- 业务复杂度:当if-else超过5层时就该考虑DDD了
- 团队规模:10人以上的团队需要清晰的上下文边界
- 变更频率:高频变更的业务适合用DDD建立稳定模型
- 性能需求: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;
}
}
选择建议:
适合三层架构的场景:
- 简单CRUD应用
- 短期快速迭代的项目
- 业务规则简单的内部系统
适合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;
}
}
关键注意事项:
- 不要为了DDD而DDD:适合的才是最好的
- 渐进式改造:可以先从核心域开始
- 统一语言:建立团队通用的术语表
- 技术债务管理:明确架构边界
五、总结与展望
经过上面的对比分析,我们可以得出:
- 三层架构就像瑞士军刀,简单实用但功能有限
- DDD像专业工具包,针对复杂场景但学习成本高
- 现代架构趋势是混合使用:核心域用DDD,支撑子域用三层
- 未来可能会涌现更多面向特定场景的架构模式
无论选择哪种架构,记住架构的本质是管理复杂度。好的架构应该像城市交通系统,既要有主干道(核心域),也要有小巷子(简单功能),各司其职又有机统一。
评论