DDD分层架构下UI层是否需引用DomainModel.dll的技术咨询
DDD分层架构:UI层是否需要引用领域模型程序集?
首先直接给结论:你当前让UI层引用DomainModel.dll的做法不符合DDD分层的设计原则,UI层只需要引用AppService.dll就足够了。下面我来拆解问题原因,以及给出正确的实现方式:
为什么当前做法不对?
在DDD的分层体系里,核心原则是依赖倒置+分层隔离:上层(UI、应用服务)应该依赖下层的抽象,而不是具体实现;同时最外层的UI层不应该直接接触核心的领域模型层。领域模型是业务逻辑的核心,需要被保护起来,避免上层代码随意依赖领域实体或仓储接口,否则会导致领域逻辑的内聚性被破坏,后续维护成本飙升。
你现在的困境源于手动在UI层实例化StudentService,不得不自己提供IRepository<StudentEntity>的实例——这就迫使UI层必须拿到StudentEntity和IRepository<T>的定义,只能去引用DomainModel.dll。但这完全是可以避免的。
正确的解决思路:用依赖注入容器管理依赖
要打破这个僵局,你需要引入依赖注入(DI)容器(比如Autofac、微软自带的Microsoft.Extensions.DependencyInjection)来统一管理所有对象的创建和依赖注入。这样UI层根本不需要关心仓储怎么实例化,只需要从容器里拿应用服务就行。
具体步骤&代码示例
- 先实现仓储的具体类(通常放在Infrastructure层,比如单独的Infrastructure.dll,这个层引用DomainModel.dll):
// Infrastructure.dll public class SqlStudentRepository : IRepository<StudentEntity> { public void Insert(StudentEntity entity) { // 这里写实际的数据库插入逻辑 } }
- 在应用启动时注册所有依赖(这个注册逻辑可以放在UI层的启动代码里,或者单独的配置类中,不需要UI层直接引用DomainModel.dll,因为可以通过程序集扫描来找到实现):
// 以微软DI为例,UI层启动配置 var services = new ServiceCollection(); // 注册仓储:把IRepository<StudentEntity>和它的实现类绑定 services.AddScoped<IRepository<StudentEntity>, SqlStudentRepository>(); // 注册应用服务 services.AddScoped<StudentService>(); // 构建服务容器 var serviceProvider = services.BuildServiceProvider();
- UI层直接从容器获取应用服务:
// UI layer public class Main { public class Program { public void Main(string[] args) { // 从容器里拿StudentService,容器会自动把需要的仓储实例注入进去 var studentService = serviceProvider.GetRequiredService<StudentService>(); // 接下来直接调用studentService的业务方法就好,完全不用管仓储的事 } } }
进一步优化的小建议
- 给应用服务定义一个接口(比如
IStudentService),把接口放在单独的Application.Contracts.dll里,UI层只需要引用这个契约程序集,连AppService.dll都不用直接引用,解耦程度更高。 - 考虑把
IRepository<T>这类仓储抽象移到Application.Contracts或者Domain.Contracts层,而不是DomainModel.dll中,这样上层依赖的是抽象契约,而不是具体的领域实体程序集,更符合依赖倒置原则。
内容的提问来源于stack exchange,提问作者Babak Golkar
相关产品推荐
相关产品推荐

