这是一个关于如何最好地进行DI的问题,因此它不依赖于任何特定的DI / IoC框架,因为,框架应该根据模式和实践而不是相反的方式选择,不是吗?
我正在做一个项目,其中存储库必须注入服务,服务可能需要多个存储库,我对以下方法之间的利弊感到好奇:
在服务构造函数中注入存储库
public class SomeService : ISomeService
{
private IRepository1 repository1;
private IRepository2 repository2;
public SomeService(IRepository1 repository1, IRepository2 repository2)
{
this.repository1 = repository1;
this.repository2 = repository2;
}
public void DoThis()
{
//Do something with repository1
}
public void DoThat()
{
//Do something with both repository1 and repository2
}
}
注入一个自定义上下文类,其中包含任何服务可能需要但延迟实例化的所有内容(IServiceContext将是BaseService中的受保护字段)
public class SomeService : BaseService, ISomeService
{
public SomeService(IServiceContext serviceContext)
{
this.serviceContext= serviceContext;
}
public void DoThis()
{
//Do something with serviceContext.repository1
}
public void DoThat()
{
//Do something with both serviceContext.repository1 and serviceContext.repository2
}
}
只注入需要它们的方法
public class SomeService : ISomeService
{
public void DoThis(IRepository1 repository1)
{
//Do something with repository1
}
public void DoThat(IRepository1 repository1, IRepository2 repository2)
{
//Do something with both repository1 and repository2
}
}
我们应该赞赏一些指示,而且在评估这些替代方案时我应该考虑哪些方面?
答案 0 :(得分:8)
注入依赖项的首选方法是 Constructor Injection 。
方法注入不太理想,因为这很快就会导致必须传递从服务到服务的许多依赖关系,并且会导致实现细节(依赖关系)通过API泄漏(您的方法) )。
选项1和2都执行构造函数注入,这很好。如果您发现自己必须在构造函数中注入太多依赖项,则会出现问题。你违反了Single Responsibility Principle,或者你错过了某种aggregate service,这就是你在选项2中所做的。
但是,在您的情况下,您的IServiceContext
聚合服务正在将多个存储库组合在一起。一个类后面的许多存储库对我来说都像unit of work。只需向Commit
添加IServiceContext
方法,您就一定会拥有工作单元。想一想:你不想在你的服务中注入IUnitOfWork
吗?
答案 1 :(得分:3)
第一种选择似乎是DI中最自然的选择。服务类需要两个存储库来执行其功能,因此为了构造实例而需要它们在语义上(并且实际上)是有意义的。
第二个选项听起来有点像服务位置,通常被认为是反模式(参见http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx)。简而言之,它创建了隐式依赖关系,其中显式依赖关系始终是首选。
答案 2 :(得分:1)
我会做基于构造函数的注入或基于属性的注入。我将不传递包含依赖项的上下文,除非该上下文用于其他目的。
我更喜欢基于构造函数的注入以获得所需的依赖关系,因为如果缺少某些东西,它会使对象创建变得非常容易。我是从here得到的。如果要验证是否满足了依赖关系,则必须使用基于构造函数的注入,因为无法确定哪个setter是最后一个要触发的setter。