依赖注入的最佳实践

时间:2011-10-05 17:50:22

标签: service dependency-injection repository

这是一个关于如何最好地进行DI的问题,因此它不依赖于任何特定的DI / IoC框架,因为,框架应该根据模式和实践而不是相反的方式选择,不是吗?

我正在做一个项目,其中存储库必须注入服务,服务可能需要多个存储库,我对以下方法之间的利弊感到好奇:

  1. 在服务构造函数中注入存储库

    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
        }
    }
    
  2. 注入一个自定义上下文类,其中包含任何服务可能需要但延迟实例化的所有内容(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
        }
    }
    
  3. 只注入需要它们的方法

    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
        }
    }
    
  4. 我们应该赞赏一些指示,而且在评估这些替代方案时我应该考虑哪些方面?

3 个答案:

答案 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。