Внедрить зависимости в методы или в конструктор? - PullRequest
20 голосов
/ 17 октября 2008

Инъекция зависимости, кажется, хорошая вещь. Вообще, должны ли зависимости быть внедрены в методы, которые требуют их, или они должны быть вставлены в конструктор класса?

См. Примеры ниже, чтобы продемонстрировать два способа внедрения одной и той же зависимости.

//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 ]

14 голосов
/ 17 октября 2008

Основным преимуществом внедрения в конструктор является то, что он позволяет помечать ваши поля как окончательные. Например:

class Foo {
    private final Bar _bar;

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

На следующей странице представлен большой список плюсов и минусов: Guice Best Practices :

Метод введения

  • + Это не полевая инъекция
  • + Единственное, что работает для некоторых странных крайних случаев

Конструктор инъекций

  • + Поля могут быть окончательными!
  • + Впрыск невозможно пропустить
  • + Легко увидеть зависимости с первого взгляда
  • + В этом и заключается идея строительства
  • - Без дополнительных инъекций
  • - бесполезно, когда библиотека DI не может сама создать экземпляр
  • - Подклассы должны "знать о" инъекциях, необходимых их суперклассам
  • - менее удобно для тестов, которые "заботятся" только об одном из параметров
3 голосов
/ 27 октября 2008

Если вы вводите во время методов, то вы не отличаете поведенческую абстракцию от конкретных зависимостей. Это большой нет нет :). Вы хотите зависеть от абстракций, поэтому вы не связаны с зависимостями ваших классов. , ,

Поскольку ваш конструктор не будет присутствовать ни в одном интерфейсе, который поддерживает ваш конкретный класс, вы не привязаны к этой зависимости. Но вызовы методов будут иметь эту проблему.

Вот хорошая статья на эту тему:

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

3 голосов
/ 17 октября 2008

Не вводя зависимость в каждый метод, вы заставляете каждого вызывающего абонента знать или получать зависимость.

Кроме того, с точки зрения инструментария доступно много платформ (по крайней мере, в .NET), которые позволяют или упрощают внедрение конструктора. Это не должно повлиять на решение, но сделает его намного привлекательнее.

Удачи.

2 голосов
/ 17 октября 2008

Другой метод заключается в использовании установщика для зависимости. Иногда это сочетается с инжектором конструктора. Это может быть полезно, если вы хотите изменить, какую реализацию вы используете позже, без необходимости заново создавать экземпляр.

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();
   }
}
1 голос
/ 17 октября 2008

Сумасшедший Боб Ли говорит, что по возможности используйте инъекцию в конструктор. Используйте внедрение метода только тогда, когда у вас нет контроля над реализацией (как в сервлете).

...