Dependency Injection: когда следует использовать property injection?

2

В каких случаях имеет смысл использовать property injection вместо constructor injection? И стоит ли так вообще делать? Понятно, что жизненно важные зависимости нужно инжектить через конструктор. Но разве бывают "не важные"? Если классу требуется какая-то зависимость, то она в любом случае важна для него.

Поделитесь мыслями на этот счет.

Новые ответы


1

Если у вас есть такой код (это из реального приложения):

TestIssue = new Issue(Id, ProjectId, ProjectName, Code, Title,  
    Description, CategoryId, CategoryName, PriorityId,
    PriorityName,PriorityImageUrl, StatusId, StatusName, 
    StatusImageUrl, IssueTypeId, IssueTypeName,IssueTypeImageUrl,
    ResolutionId, ResolutionName,ResolutionImageUrl, 
    AssignedDisplayName, AssignedUsername, AssignedUserId,
    CreatorDisplayName, CreatorUsername, CreatorUserId, 
    OwnerDisplayName, OwnerUsername, OwnerUserId, DueDate, 
    MilestoneId, MilestoneName, MilestoneImageUrl, 
    MilestoneDueDate, AffectedMilestoneId, AffectedMilestoneName, 
    AffectedMilestoneImageUrl, Visibility, TimeLogged, Estimation, 
    DateCreated, LastUpdate, LastUpdateUsername, 
    LastUpdateDisplayName, Progress, Disabled, Votes);

То, наверное, стОит задуматься о property injection) Кому интересно, но не хочется считать — конструктор принимает 47 аргументов.

1

Есть и такое радикальное мнение, что property injection можно использовать всегда. Большая куча свойств лучше большой кучи параметров конструктора. И с эстетической и с практической точки зрения. Единственное неудобство — при создании из IOC контейнера нет гарантии что клиент получает объект, у которого все свойства заполнены. Но на этот случай можно написать метод, проверяющий корректность всех свойств и выкидывающий exception в случае если что-то не проинжектилось. Большинство IOC-контейнеров поддерживают вызов init-методов после создания объекта. В итоге мы получаем: с одной стороны, в ioc контейнере осуществляется «строгая» проверка того что все свойства заполнены; с другой стороны, в любом другом месте (в юнит тестах, напрмер) мы можем легко обойти эту проверку и задавать только те свойства, которые нам нужны.

safonovea

Вариант ясен, спасибо :)

2

Вот отрывок из справки по Spring.NET

Команда Spring обычно оправдывает использование setter injection, потому что из-за большого числа аргументов конструктор может стать слишком громоздким, особенно когда некоторые параметры опциональны. Наличие setter-методов также дает возможность повторной инъекции зависимостей после создания объекта.

Считается, что настоящие мужчины неизменно выбирают constructor-injection, и на это есть причины. Передача ВСЕХ требуемых зависимостей означает, что клиент никогда не получит экземпляр, который инициализирован не полностью. Обратная сторона в том, что объект уже невозможно переконфигурировать.

Однако, строгого правила здесь нет. Доверьтесь Силе и выбирайте тот тип инъекции, который считаете подходящим; иногда, когда вы имеете дело со сторонними библиотеками, выбор уже сделам за вас — классы могут не иметь setter-методов и придется использовать конструктор.

Так как вы можете смешивать оба подхода, лучшее правило — использовать конструктор для необходимых зависимостей и сеттеры для опциональных.

safonovea

Да, это все хорошо, но повторю вопрос — как же отличить необходимую зависимость от опциональной?

Чак Норрис

Тут много вариантов. Например, конфигуровочные параметры (они обычно примитивных типов) не являются жизненно необходимыми. Или такой случай — в классе есть 10 методов, каждый из них использует одну общую зависимость и несколько специфичных. Так вот та зависимость, которая используется всеми методами, является строго обязательной, а остальные опциональны...

Чак Норрис

... И если я пишу unit test на один из этих методов, я не хочу в конструктор передавать ВСЕ зависимости. Мне удобнее через сетторы задать только НУЖНЫЕ.

Чак Норрис

Можно сформулировать такое правило: все зависимости, БЕЗ которых класс способен выполнять хотя бы часть своей функциональности, можно признать второстепенными

1

Конечно предпочтительнее использовать constructor injection. Но есть некоторые проблемы.

  • Конструктор класса может вызываться в нескольких местах, а не только в IOC-контейнере. При этом по мере добавления в класс все новых и новых зависимостей придется менять все участки кода где вызывается конструктор. В этом случае property injection для некоторых зависимостей выглядит удобнее.
  • Класс может требовать так много зависимостей, что конструктор будет выглядеть ужасно принимая все эти параметры.
safonovea

Т.е. можно сделать вывод — нужно использовать конструктор по мере возможности. Свойства — как запасной вариант, на случай если инъекция через конструктор становится чрезмерно сложной и трудноподдерживаемой.

P.S. Грань "чрезмерно сложности и трудноподдерживаемости" как всегда каждый определяет для себя сам :)


v1.7.123.556
© 2009—2010 CodeHelper FAQ | О сайте | Обратная связь | История изменений | Статьи
Creative Commons LicenseМатериалы сайта распространяются под лицензией Creative Commons Attribution-Share Alike 3.0 Unported.