假设我有一些DDD服务需要一些IEnumerable<Foo>
来执行一些计算。我想出了两种设计:我是否应该将存储库接口与域模型分离
摘要与
IFooRepository
接口的数据访问,这是相当典型的public class FooService { private readonly IFooRepository _fooRepository; public FooService(IFooRepository fooRepository) => _fooRepository = fooRepository; public int Calculate() { var fooModels = _fooRepository.GetAll(); return fooModels.Sum(f => f.Bar); } }
不要依赖
IFooRepository
抽象和注入IEnumerable<Foo>
直接public class FooService { private readonly IEnumerable<Foo> _foos; public FooService(IEnumerable<Foo> foos) => _foos = foos; public int Calculate() => _foos.Sum(f => f.Bar); }
这第二个设计s在我看来,更好的是FooService
现在不关心数据来自何处,Calculate
变成纯粹的域逻辑(忽略IEnumerable
可能来自不纯的来源)。
使用第二个设计另一种说法是,当IFooRepository
通过网络进行异步IO,它通常会希望使用async-await
,如:
public class AsyncDbFooRepository : IFooRepository
{
public async Task<IEnumerable<Foo>> GetAll()
{
// Asynchronously fetch results from database
}
}
但是当你需要async all the way down,FooService
现在不得不将其签名更改为async Task<int> Calculate()
。这似乎违反了dependency inversion principle。
但是,第二个设计也存在问题。首先,你必须依靠的DI容器(使用简单注射器在这里举例),或组成根源上解决,如数据访问代码:
public class CompositionRoot
{
public void ComposeDependencies()
{
container.Register<IFooRepository, AsyncDbFooRepository>(Lifestyle.Scoped);
// Not sure if the syntax is right, but it demonstrates the concept
container.Register<FooService>(async() => new FooService(await GetFoos(container)));
}
private async Task<IEnumerable<Foo>> GetFoos(Container container)
{
var fooRepository = container.GetInstance<IFooRepository>();
return await fooRepository.GetAll();
}
}
而且在我的具体情况,AsyncDbFooRepository
需要某种的运行参数来构建,这意味着您需要一个abstract factory来构造AsyncDbFooRepository
。
随着抽象工厂,现在我必须管理所有依赖AsyncDbFooRepository
(AsyncDbFooRepository
下的对象图是不平凡的)的生命周期。我有一种预感,如果我选择第二种设计,我会错误地使用DI。
总之,我的问题是:
- 我在我的第二个设计不当使用DI?
- 我该如何为我的第二个设计令人满意地构建我的依赖关系?
如果Foo是运行时数据,则不应将其注入到组件构造函数中。阅读:https://cuttingedge.it/blogs/steven/pivot/entry.php?id = 99 – Steven
感谢您的链接。根据你的博客,我应该注入'AsyncDbFooRepository'而不是(首次设计),但是这不会违反依赖倒置原则(如问题所述)吗? – rexcfnghk
我会建议你使用存储库层。您可以拥有SqlFooRepository,FileSystemFooRepository,Neo4JFooRepository等。您可以从数据更改位置获取好处。如果您在构造函数中通过IEnumerable,则会限制自己,例如将数据添加回存储库,删除等。 –
user1628733