构造函数注入的优点是,它使依赖关系显式,并强制客户端提供实例。它还可以保证客户端以后不能更改实例。一个(可能的)缺点是您必须向构造函数添加一个参数。
Setter注入的优点是不需要向构造函数添加参数。它还不需要客户端设置实例。这对于可选的依赖项很有用。如果您希望类在默认情况下创建一个真实的数据存储库,那么这也可能很有用,例如,在测试中,您可以使用setter将其替换为测试实例。
据我所知,接口注入与二传手注入没有太大区别。在这两种情况下(可选),您都设置了一个以后可以更改的依赖项。
最终,这取决于偏好以及是否需要依赖关系。我个人几乎只使用构造函数注入。我喜欢通过强制客户端在构造函数中提供实例来使类的依赖关系显式化。我也喜欢客户端不能在事后更改实例。
通常,我传递两个单独的实现的唯一原因是进行测试。在生产中,我可以通过DataRepository
,但在测试中,我可以通过FakeDataRepository
。在这种情况下,我通常将提供两个构造函数:一个没有参数,另一个接受a IDataRepository
。然后,在没有参数的构造函数中,我将调用链接到第二个构造函数并传递new DataRepository()
。
这是C#中的示例:
public class Foo
{
private readonly IDataRepository dataRepository;
public Foo() : this(new DataRepository())
{
}
public Foo(IDataRespository dataRepository)
{
this.dataRepository = dataRepository;
}
}
这就是所谓的穷人依赖注射。我喜欢它,因为在生产客户端代码中,我不需要通过重复几个看起来像这样的语句来重复自己
var foo = new Foo(new DataRepository());
但是,我仍然可以通过替代实现进行测试。我意识到,使用穷人的DI可以对依赖项进行硬编码,但这对我来说是可以接受的,因为我主要使用DI进行测试。