Внедрение зависимостей через конструктор или сеттер собственность?
Я рефакторинг класса и добавление новой зависимости к нему. В настоящее время класс принимает свои существующие зависимости в конструкторе. Поэтому для согласованности я добавляю параметр в конструктор.
Конечно, есть несколько подклассов плюс еще больше для модульных тестов, поэтому теперь я играю в игру, изменяя все конструкторы, чтобы соответствовать, и это занимает годы.
Это заставляет меня думать, что использование свойств с сеттерами является лучшим способом получения зависимостей. Я не думайте, что введенные зависимости должны быть частью интерфейса для построения экземпляра класса. Вы добавляете зависимость, и теперь все ваши пользователи (подклассы и любой, кто создает вас напрямую) внезапно узнают об этом. Это похоже на разрыв инкапсуляции.
Это не похоже на шаблон с существующим кодом здесь, поэтому я ищу, чтобы узнать, что такое общий консенсус, плюсы и минусы конструкторов против свойств. С помощью сеттеров собственность лучше?
14 ответов:
Ну, это зависит :-).
Если класс не может выполнить свою работу без зависимости, добавьте его в конструктор. Класс должен новая зависимость, так что вы хотите изменить, чтобы ломать вещи. Кроме того, создание класса, который не полностью инициализирован ("двухэтапная конструкция"), является анти-шаблоном (IMHO).
Если класс может работать без зависимости, сеттер в порядке.
пользователи класса должно чтобы узнать о зависимостях данного класса. Если бы у меня был класс, который, например, подключен к базе данных, и не предоставлял средства для внедрения зависимости уровня персистентности, пользователь никогда не знал бы, что соединение с базой данных должно быть доступно. Однако, если я изменю конструктор, я дам пользователям знать, что существует зависимость от уровня сохраняемости.
кроме того, чтобы предотвратить себя от того, чтобы изменить при каждом использовании старого конструктора просто применяйте цепочку конструкторов в качестве временного моста между старым и новым конструктором.
public class ClassExample { public ClassExample(IDependencyOne dependencyOne, IDependencyTwo dependencyTwo) : this (dependnecyOne, dependencyTwo, new DependnecyThreeConcreteImpl()) { } public ClassExample(IDependencyOne dependencyOne, IDependencyTwo dependencyTwo, IDependencyThree dependencyThree) { // Set the properties here. } }одной из точек внедрения зависимостей является выявление того, какие зависимости имеет класс. Если класс имеет слишком много зависимостей, то это может быть время для некоторого рефакторинга: каждый метод класса использует все зависимости? Если нет, то это хорошая отправная точка, чтобы увидеть, где класс может быть разделена.
конечно, установка конструктора означает, что вы можете проверить все сразу. Если вы назначаете вещи в поля только для чтения, то у вас есть некоторые гарантии о зависимостях вашего объекта прямо со времени строительства.
Это настоящая боль, добавляющая новые зависимости, но по крайней мере таким образом компилятор продолжает жаловаться, пока это не будет правильно. Это хорошо, я думаю.
Если у вас есть большое количество дополнительных зависимостей (что уже запах), то, вероятно, инъекция сеттера-это путь. Однако инъекция конструктора лучше показывает ваши зависимости.
общий предпочтительный подход заключается в использовании инъекции конструктора как можно больше.
инъекция конструктора точно указывает, какие необходимы зависимости для правильной работы объекта - ничто не раздражает больше, чем создание объекта и его сбой при вызове метода на нем, потому что некоторая зависимость не установлена. Объект, возвращаемый конструктором, должен находиться в рабочем состоянии.
попробуйте иметь только один конструктор, он сохраняет дизайн просто и избегает двусмысленности (если не для людей, то для контейнера DI).
вы можете использовать инъекцию свойств, когда у вас есть то, что Марк Seemann называет локальное значение по умолчанию в своей книге "инъекция зависимостей в .NET": зависимость необязательна, потому что вы можете обеспечить прекрасную рабочую реализацию, но хотите, чтобы вызывающий мог указать другой, если это необходимо.
(прежний ответ ниже)
Я думаю, что инъекция конструктора лучше, если инъекция обязательна. Если это добавляет слишком много конструкторов, рассмотрите возможность использования фабрик вместо конструкторов.
впрыска сеттера славна если впрыска опционная, или если вы хотите изменить ее наполовину ринв. Я вообще не люблю сеттеров, но это дело вкуса.
Это во многом вопрос личного вкуса. Лично я предпочитаю инъекцию сеттера, потому что я считаю, что это дает вам больше гибкости в том, как вы можете заменить реализации во время выполнения. Кроме того, конструкторы с большим количеством аргументов не являются чистыми, на мой взгляд, и аргументы, представленные в конструкторе, должны быть ограничены необязательными аргументами.
пока интерфейс классов (API) понятен в том, что ему нужно для выполнения своей задачи, Ты хороший.
лично я предпочитаю извлечь и заменить "шаблон" над инъекционными зависимостями в конструкторе, в основном по причине, изложенной в вашем вопросе. Вы можете установить свойства, как
virtualи затем переопределить реализацию в производном тестируемом классе.
Я предпочитаю инъекции конструктора, потому что это помогает "принудительно" требования к зависимостям класса. Если это в конструктор, потребитель и установить объекты, чтобы получить приложение для компиляции. Если вы используете инъекцию setter, они могут не знать, что у них есть проблема до времени выполнения - и в зависимости от объекта это может быть поздно во время выполнения.
Я все еще использую инъекцию сеттера время от времени, когда вводимый объект, возможно, нуждается в куче самой работы, например инициализация.
Я perfer инъекцию конструктора, потому что это кажется наиболее логичным. Это как сказать мой класс требует эти зависимости выполняют свою работу. Если это необязательная зависимость, то свойства кажутся разумными.
Я также использую инъекцию свойств для установки вещей, на которые контейнер не имеет ссылок, таких как ASP.NET просмотр презентации, созданной с помощью контейнера.
Я не думаю, что это нарушает инкапсуляцию. Внутренние работы должны остаться внутренние и зависимости имеют дело с другой проблемой.
один из вариантов, который может быть стоит рассмотреть, - это создание сложных множественных зависимостей из простых одиночных зависимостей. То есть определить дополнительные классы для составных зависимостей. Это делает вещи немного проще WRT инъекции конструктора-меньше параметров на вызов - в то же время сохраняя must-supply-all-dependencies-to-instantiate вещь.
конечно, это имеет смысл, если есть какая-то логическая группировка зависимостей, поэтому соединение больше, чем произвольная совокупность, и это имеет наибольший смысл, если есть несколько зависимостей для одной составной зависимости - но блок параметров "шаблон" существует уже давно, и большинство из тех, которые я видел, были довольно произвольными.
лично я больше поклонник использования методов / установщиков свойств для указания зависимостей, параметров и т. д. Имена вызовов помогают описать, что происходит. Это хорошая идея, чтобы предоставить пример этого-это-как-настроить-его-фрагменты, хотя, и убедитесь, что зависимый класс выполняет достаточно проверок ошибок. Возможно, вы захотите использовать конечную модель состояния для настройки.
недавно столкнулся с ситуацией где у меня было несколько зависимостей в классе, но только одна из зависимостей неизбежно будет меняться в каждой реализации. Поскольку зависимости доступа к данным и регистрации ошибок, скорее всего, будут изменены только для целей тестирования, я добавил дополнительные параметры для этих зависимостей и при условии реализации по умолчанию этих зависимостей в моем коде конструктора. Таким образом, класс сохраняет свое значение по умолчанию поведение, если оно не переопределено потребителем класса.
использование необязательных параметров может быть выполнено только в платформах, которые их поддерживают, таких как .NET 4 (как для C#, так и для VB.NET хотя ... VB.NET всегда имел их). Конечно, вы можете выполнить подобную функциональность, просто используя свойство, которое может быть переназначено потребителем вашего класса, но вы не получаете преимущества неизменности, обеспечиваемого наличием объекта частного интерфейса, назначенного параметру класса. конструктор.
все это, как говорится, если вы вводите новую зависимость, которая должна быть предоставлена каждым потребителем, вам придется рефакторинг вашего конструктора и всего кода, который потребляет ваш класс. Мои предложения выше действительно применяются только в том случае, если у вас есть возможность предоставить реализацию по умолчанию для всего вашего текущего кода, но все же предоставить возможность переопределить реализацию по умолчанию, если это необходимо.
Это старый пост, но если он понадобится в будущем, возможно, это будет полезно:
https://github.com/omegamit6zeichen/prinject
У меня была похожая идея, и я придумал эту структуру. Это, вероятно, далеко не полный, но это идея структуры, ориентированной на инъекцию свойств
Это зависит от того, как вы хотите реализовать. Я предпочитаю инъекцию конструктора везде, где я чувствую, что значения, которые входят в реализацию, часто не меняются. Например: если compnay stragtegy идет с сервером oracle, я настрою свои значения datsource для соединений bean achiveing через инъекцию конструктора. В противном случае , если мое приложение является продуктом и может подключаться к любой БД клиента, я бы реализовал такую конфигурацию БД и реализацию нескольких брендов через сеттер инъекция. Я только что взял пример, но есть лучшие способы реализации сценариев, о которых я упоминал выше.
инъекция конструктора явно раскрывает зависимости, делая код более читаемым и менее подверженным необработанным ошибкам во время выполнения, если аргументы проверяются в конструкторе, но это действительно сводится к личному мнению, и чем больше вы используете DI, тем больше вы будете склонны качаться назад и вперед так или иначе в зависимости от проекта. У меня лично есть проблемы с кодом пахнет конструкторами с длинным списком аргументов, и я чувствую, что потребитель объекта должен знать зависимости для того, чтобы использовать объект в любом случае, так что это делает случай для использования инъекции свойств. Мне не нравится неявный характер инъекции свойств, но я нахожу его более элегантным, что приводит к более чистому коду. Но с другой стороны, инъекция конструктора предлагает более высокую степень инкапсуляции, и по моему опыту я стараюсь избегать конструкторов по умолчанию, поскольку они могут плохо влиять на целостность инкапсулированных данных, если не быть осторожным.
выбрать инъекция конструктором или свойством мудро на основе вашего конкретного сценария. И не думайте, что вам нужно использовать DI только потому, что это кажется необходимым, и это предотвратит плохой дизайн и запахи кода. Иногда это не стоит усилий, чтобы использовать шаблон, если усилия и сложности перевешивают преимущества. Пусть все будет просто.
Comments