Я занимаюсь рефакторингом класса и добавляю в него новую зависимость. В настоящее время класс принимает существующие зависимости в конструкторе. Поэтому для согласованности я добавляю параметр в конструктор.
Конечно, есть несколько подклассов и даже больше для модульных тестов, так что теперь я играю в игру, изменяя все конструкторы, чтобы соответствовать, и это требует времени.
Это заставляет меня думать, что использование свойств с установщиками - лучший способ получения зависимостей. Я не думаю, что внедренные зависимости должны быть частью интерфейса для создания экземпляра класса. Вы добавляете зависимость, и теперь все ваши пользователи (подклассы и все, кто создает для вас экземпляр) внезапно узнают об этом. Это похоже на разрыв инкапсуляции.
Это не похоже на шаблон с существующим кодом, поэтому я хочу выяснить, каково общее согласие, плюсы и минусы конструкторов в сравнении со свойствами. Лучше ли использовать установщики свойств?
источник
Пользователи в классе должны знать о зависимости данного класса. Если бы у меня был класс, который, например, подключался к базе данных и не предоставлял средства для внедрения зависимости постоянного уровня, пользователь никогда бы не узнал, что соединение с базой данных должно быть доступно. Однако, если я изменю конструктор, я сообщу пользователям, что существует зависимость от уровня персистентности.
Кроме того, чтобы избежать необходимости изменять каждое использование старого конструктора, просто примените цепочку конструктора как временный мост между старым и новым конструктором.
Одной из точек внедрения зависимостей является выявление зависимостей класса. Если у класса слишком много зависимостей, возможно, пора провести рефакторинг: использует ли каждый метод класса все зависимости? Если нет, то это хорошая отправная точка, чтобы увидеть, где класс может быть разделен.
источник
Конечно, добавление конструктора означает, что вы можете проверить все сразу. Если вы назначаете вещи в поля только для чтения, то у вас есть некоторые гарантии относительно зависимостей вашего объекта прямо со времени создания.
Добавление новых зависимостей - это настоящая боль, но, по крайней мере, таким образом компилятор продолжает жаловаться до тех пор, пока не станет правильным. Это хорошая вещь, я думаю.
источник
Если у вас есть большое количество необязательных зависимостей (которые уже пахнут), то, вероятно, инъекция сеттера - путь. Внедрение в конструктор лучше раскрывает ваши зависимости.
источник
Общий предпочтительный подход заключается в максимально возможном использовании инжектора конструктора.
Внедрение в конструктор точно определяет, какие требуются зависимости для правильного функционирования объекта - нет ничего более раздражающего, чем обновление объекта и его сбой при вызове метода, потому что некоторая зависимость не установлена. Объект, возвращаемый конструктором, должен находиться в рабочем состоянии.
Старайтесь иметь только один конструктор, он сохраняет дизайн простым и позволяет избежать двусмысленности (если не для людей, для контейнера DI).
Вы можете использовать внедрение свойств, когда у вас есть то, что Марк Симанн называет локальным значением по умолчанию в своей книге «Внедрение зависимостей в .NET»: зависимость является необязательной, поскольку вы можете обеспечить работоспособную реализацию, но хотите, чтобы вызывающая сторона указывала другую, если необходимо.
(Бывший ответ ниже)
Я думаю, что инъекция в конструктор лучше, если инъекция обязательна. Если это добавляет слишком много конструкторов, рассмотрите возможность использования фабрик вместо конструкторов.
Инъекция сеттера хороша, если инъекция не обязательна, или если вы хотите изменить ее на полпути. Я вообще не люблю сеттеров, но это дело вкуса.
источник
Это во многом вопрос личного вкуса. Лично я предпочитаю инъекцию сеттера, потому что считаю, что это дает вам больше гибкости в способе замены реализаций во время выполнения. Кроме того, конструкторы с большим количеством аргументов, на мой взгляд, не являются чистыми, и аргументы, представленные в конструкторе, должны быть ограничены необязательными аргументами.
Пока интерфейс классов (API) понятен в том, что ему нужно для выполнения своей задачи, у вас все хорошо.
источник
Я лично предпочитаю «шаблон» « Извлечь и переопределить », а не вводить зависимости в конструктор, в основном по причине, изложенной в вашем вопросе. Вы можете установить свойства как
virtual
и затем переопределить реализацию в производном тестируемом классе.источник
Я предпочитаю внедрение конструктора, потому что оно помогает «обеспечить» требования к зависимости класса. Если это в c'or, потребитель должен установить объекты, чтобы приложение компилировалось. Если вы используете сеттерную инъекцию, они могут не знать, что у них есть проблема, до времени выполнения - и в зависимости от объекта это может быть поздно во время выполнения.
Я до сих пор время от времени использую сеттерную инъекцию, когда внедренному объекту, возможно, нужна куча работы, например, инициализация.
источник
Я предпочитаю внедрение конструктора, потому что это кажется наиболее логичным. Это все равно что сказать, что мой класс требует, чтобы эти зависимости выполняли свою работу. Если это необязательная зависимость, то свойства кажутся разумными.
Я также использую инъекцию свойств для установки вещей, на которые у контейнера нет ссылок, таких как представление ASP.NET на презентаторе, созданном с использованием контейнера.
Я не думаю, что это нарушает инкапсуляцию. Внутренняя работа должна оставаться внутренней, а зависимости связаны с другой проблемой.
источник
Один из вариантов, который может стоить рассмотреть, - это составление сложных множественных зависимостей из простых одиночных зависимостей. То есть определить дополнительные классы для составных зависимостей. Это немного упрощает внедрение конструктора WRT - меньшее количество параметров на вызов - и в то же время поддерживает необходимость обязательного предоставления всех зависимостей для создания экземпляра.
Конечно, это имеет смысл, если есть какая-то логическая группировка зависимостей, поэтому соединение представляет собой нечто большее, чем произвольный агрегат, и это имеет смысл, если существует несколько зависимостей для одной составной зависимости, но блок параметров "pattern" имеет был вокруг в течение долгого времени, и большинство из тех, что я видел, были довольно произвольны.
Лично я больше фанат использования методов / установщиков свойств для определения зависимостей, опций и т. Д. Имена вызовов помогают описать происходящее. Хорошей идеей будет привести примеры фрагментов «это как установить» и убедиться, что зависимый класс выполняет достаточное количество проверок ошибок. Возможно, вы захотите использовать модель конечного состояния для установки.
источник
Недавно я столкнулся с ситуацией, когда у меня было несколько зависимостей в классе, но в каждой реализации обязательно менялась только одна из зависимостей. Поскольку зависимости доступа к данным и регистрации ошибок, скорее всего, будут изменены только для целей тестирования, я добавил необязательные параметры для этих зависимостей и предоставил реализации этих зависимостей по умолчанию в своем коде конструктора. Таким образом, класс сохраняет свое поведение по умолчанию, если только он не переопределен потребителем класса.
Использование необязательных параметров может быть выполнено только в средах, которые их поддерживают, таких как .NET 4 (как для C #, так и для VB.NET, хотя в VB.NET они всегда были). Конечно, вы можете реализовать аналогичную функциональность, просто используя свойство, которое может быть переназначено потребителем вашего класса, но вы не получаете преимущества неизменности, обеспечиваемого наличием объекта частного интерфейса, назначенного параметру конструктора.
Все это, как говорится, если вы вводите новую зависимость, которая должна предоставляться каждым потребителем, вам придется реорганизовать ваш конструктор и весь код, который потребляет ваш класс. Мои предложения, приведенные выше, действительно применимы только в том случае, если вы можете позволить себе реализацию по умолчанию для всего вашего текущего кода, но при этом можете при необходимости переопределить реализацию по умолчанию.
источник
Это старый пост, но если он понадобится в будущем, возможно, он будет полезен:
https://github.com/omegamit6zeichen/prinject
У меня была похожая идея, и я придумал эту структуру. Это, вероятно, далеко от завершения, но это идея структуры, ориентированной на внедрение свойств
источник
Это зависит от того, как вы хотите реализовать. Я предпочитаю внедрение в конструктор везде, где чувствую, что значения, которые входят в реализацию, меняются не часто. Например: если стратегия compnay идет с сервером oracle, я настрою значения моего источника данных для соединения bean-компонента, получающего соединения посредством внедрения в конструктор. В противном случае, если мое приложение является продуктом и, скорее всего, оно может подключиться к любой базе данных клиента, я бы реализовал такую конфигурацию базы данных и реализацию нескольких брендов посредством внедрения сеттера. Я только что взял пример, но есть более эффективные способы реализации сценариев, которые я упомянул выше.
источник
Внедрение в конструктор явно выявляет зависимости, делая код более читабельным и менее подверженным необработанным ошибкам во время выполнения, если аргументы проверяются в конструкторе, но это действительно сводится к личному мнению, и чем больше вы используете DI, тем больше вы будете использовать имеют тенденцию качаться взад и вперед так или иначе в зависимости от проекта. У меня лично есть проблемы с запахами кода как конструкторы с длинным списком аргументов, и я чувствую, что потребитель объекта должен знать зависимости, чтобы в любом случае использовать объект, так что это оправдывает использование внедрения свойств. Мне не нравится неявная природа внедрения свойств, но я нахожу это более элегантным, в результате чего код выглядит чище. Но с другой стороны, инъекция в конструктор предлагает более высокую степень инкапсуляции,
Выбирайте инъекцию по конструктору или по свойству в зависимости от конкретного сценария. И не думайте, что вы должны использовать DI только потому, что это кажется необходимым, и это предотвратит плохой дизайн и запах кода. Иногда не стоит усилий использовать шаблон, если усилия и сложность перевешивают выгоду. Будь проще.
источник