关于依赖倒置原则(DIP):.NET项目中领域与数据访问层依赖方向的困惑
关于依赖倒置原则(DIP)与领域层、数据访问层依赖方向的困惑解答
首先得明确:你说的“依赖接口而非具体实现”确实是DIP的常见实践,但DIP的核心本质是反转依赖方向——让高层模块(领域层)主导抽象定义,低层模块(数据访问层)去适配这个抽象,而不是高层依赖低层的具体实现。
你在.NET项目里觉得“领域层必须依赖数据访问层”,其实是陷入了常规的依赖思维,用DIP可以完全反转这个方向,具体操作分三步:
在领域层定义仓储接口,比如:
// 领域层代码 public interface IOrderRepository { void SaveOrder(Order order); Order GetOrderById(Guid orderId); }领域层的业务逻辑只依赖这个接口,完全不用知道数据访问层的任何细节,比如你用EF Core还是Dapper。
在数据访问层实现这个接口,这时候数据访问层需要引用领域层项目(因为要实现领域层的接口),比如:
// 数据访问层代码 public class EfCoreOrderRepository : IOrderRepository { private readonly AppDbContext _dbContext; public EfCoreOrderRepository(AppDbContext dbContext) { _dbContext = dbContext; } public void SaveOrder(Order order) { _dbContext.Orders.Update(order); _dbContext.SaveChanges(); } public Order GetOrderById(Guid orderId) { return _dbContext.Orders.Find(orderId); } }在应用启动环节(比如ASP.NET Core的Program.cs),通过依赖注入注册实现与接口的映射:
builder.Services.AddScoped<IOrderRepository, EfCoreOrderRepository>();这样领域层在需要仓储时,直接通过构造函数注入
IOrderRepository即可,完全不用关心具体是哪个实现类。
这么做之后,依赖方向就变成了数据访问层依赖领域层,而非领域层依赖数据访问层,完全符合DIP的要求:
- 高层模块(领域层)和低层模块(数据访问层)都依赖抽象(
IOrderRepository); - 抽象(接口)不依赖细节(EF Core的DbContext、具体存储逻辑),细节依赖抽象。
你之前觉得“领域层要向仓储发送数据必须依赖数据访问层”,其实是混淆了“依赖接口”和“依赖具体实现”——领域层只需要依赖自己定义的接口,数据发送的具体逻辑由数据访问层来完成,领域层根本不需要知道数据访问层的存在。
内容的提问来源于stack exchange,提问作者Francisco Silva
相关产品推荐
相关产品推荐

