在方法或构造函数中注入依赖项?

时间:2008-10-17 18:57:56

标签: dependency-injection

依赖注入似乎是件好事。一般来说,应该在需要它们的方法中注入依赖项,还是应该在类的构造函数中注入它们?

请参阅下面的示例,以演示注入相同依赖关系的两种方法。

//Inject the dependency into the methods that require ImportantClass
Class Something {

    public Something()
    {
         //empty
    }

    public void A() 
    {
         //do something without x
    }

    public void B(ImportantClass x)
    {
         //do something with x
    }

    public void C(ImportantClass x)
    {
         //do something with x
    }
}

//Inject the dependency into the constructor once
Class Something {
    private ImportantClass _x
    public Something(ImportantClass x)
    {
         this._x = x;
    }

    public void A() 
    {
         //do something without x
    }

    public void B()
    {
         //do something with this._x
    }

    public void C()
    {
         //do something with this._x
    }

}

5 个答案:

答案 0 :(得分:14)

构造函数注入的主要好处是它允许将字段标记为final。例如:

class Foo {
    private final Bar _bar;

    Foo(Bar bar) {
        _bar=bar;
    }
}

以下页面列出了专业人士和骗子:Guice Best Practices

方法注入

  • +不是现场注入
  • +只适用于某些奇怪的边缘情况

构造函数注入

  • +菲尔兹可以是最终的!
  • +注入不可能被跳过
  • +轻松查看依赖项一目了然
  • +这就是构建的理念是什么
  • - 无可选注射
  • - 当DI库无法自己进行实例化时无用
  • - 子类需要“了解”其超类所需的注入量
  • - 对于仅“关心”其中一个参数
  • 的测试不太方便

答案 1 :(得分:3)

通过不在每个方法中注入依赖项,然后强制每个调用者知道或检索依赖项。

同样从工具的角度来看,有许多框架可用(至少在.NET中),使得构造函数注入更容易实现。这不应该影响决定,但会使其更具吸引力。

祝你好运。

答案 2 :(得分:3)

如果您在方法期间注入,则不会将行为抽象与具体依赖项区分开来。这是一个很大的没有没有:)。您希望依赖于抽象,因此您不会依赖于类依赖项的依赖项。 。 。

由于您的构造函数不会出现在您的具体类支持的任何接口中,而不是您没有耦合到该依赖项。但方法调用会有这个问题。

这是一篇关于这个问题的好文章:

http://chrisdonnan.com/blog/2007/05/20/conquest-through-extreme-composition-glue-part-2/

答案 3 :(得分:2)

另一种方法是为依赖项用户设置setter。有时这与构造函数注入相结合。如果您想要更改以后使用的实现而无需重新创建实例,这将非常有用。

public interface IFoo
{
   void Do();
}

public class DefaultFoo : IFoo
{
   public void Do()
   {
   }
}

public class UsesFoo
{
   private IFoo foo;
   public IFoo Foo
   {
       set { this.foo = value; }
   }

   public UsesFoo()
   {
      this.Foo = new DefaultFoo();
   }

   public UsesFoo( IFoo foo )
   {
      this.Foo = foo;
   }

   public void DoFoo()
   {
      this.Foo.Do();
   }
}

答案 4 :(得分:1)

Crazy Bob Lee表示尽可能使用构造函数注入。当您无法控制实例化时(例如在servlet中),仅使用方法注入。