Уже было опубликовано несколько вопросов с конкретными вопросами о внедрении зависимостей , например, когда его использовать и какие существуют для него рамки. Однако,
Что такое внедрение зависимостей и когда / почему его следует или не следует использовать?
Ответы:
Внедрение зависимости - это передача зависимости другим объектам или инфраструктуре (инжектор зависимости).
Внедрение зависимостей облегчает тестирование. Внедрение может быть сделано через конструктор .
SomeClass()
имеет конструктор следующим образом:Проблема : если
myObject
возникают сложные задачи, такие как доступ к диску или доступ к сети, трудно выполнить модульное тестированиеSomeClass()
. Программисты должны издеватьсяmyObject
и могут перехватить вызов фабрики.Альтернативное решение :
myObject
в качестве аргумента конструкторуmyObject
может быть передан напрямую, что облегчает тестирование.Сложнее выделить компоненты в модульном тестировании без внедрения зависимостей.
В 2013 году, когда я написал этот ответ, это была основная тема в блоге Google Testing . Это остается для меня самым большим преимуществом, так как программистам не всегда нужна дополнительная гибкость в их дизайне времени выполнения (например, для поиска служб или подобных шаблонов). Программисты часто должны изолировать классы во время тестирования.
источник
Лучшее определение, которое я нашел до сих пор, - это определение Джеймса Шора :
Есть статья Мартина Фаулера, которая также может оказаться полезной.
Внедрение зависимостей в основном обеспечивает объекты, в которых нуждается объект (его зависимости), вместо того, чтобы он сам их конструировал. Это очень полезный метод для тестирования, поскольку он позволяет смоделировать или заглушить зависимости.
Зависимости могут быть введены в объекты многими способами (например, инжектор конструктора или сеттер). Можно даже использовать специализированные структуры внедрения зависимостей (например, Spring), но они, конечно, не требуются. Вам не нужны эти структуры для внедрения зависимостей. Инстанцирование и передача объектов (зависимостей) в явном виде - такая же хорошая инъекция, как и внедрение через фреймворк.
источник
Я нашел этот забавный пример с точки зрения слабой связи :
Любое приложение состоит из множества объектов, которые взаимодействуют друг с другом для выполнения некоторых полезных задач. Традиционно каждый объект отвечает за получение своих собственных ссылок на зависимые объекты (зависимости), с которыми он сотрудничает. Это приводит к высокосвязанным классам и трудно тестируемому коду.
Например, рассмотрим
Car
объект.А
Car
зависит от колес, двигателя, топлива, аккумулятора и т. Д., Чтобы работать. Традиционно мы определяем марку таких зависимых объектов вместе с определениемCar
объекта.Без внедрения зависимостей (DI):
Здесь
Car
объект отвечает за создание зависимых объектов.Что если мы захотим изменить тип зависимого объекта, скажем,
Wheel
после начальныхNepaliRubberWheel()
проколов? Нам нужно воссоздать объект Car с его новой зависимостью, скажемChineseRubberWheel()
, но этоCar
может сделать только производитель.Тогда что
Dependency Injection
нам делать ...?При использовании внедрения зависимостей объектам присваиваются свои зависимости во время выполнения, а не во время компиляции (время изготовления автомобиля) . Так что теперь мы можем изменить,
Wheel
когда захотим. Здесь,dependency
(wheel
) может быть введен воCar
время выполнения.После использования зависимости зависимости:
Здесь мы инъекционные в зависимость (колесо и аккумулятор) во время выполнения. Отсюда и термин: введение зависимости.
Источник: Понимание внедрения зависимости
источник
new
есть шина? Я не. Все, что мне нужно сделать, это купить (ввести через Param) от них, установить и вау-лах! Итак, возвращаясь к программированию, скажем, проекту C # нужно использовать существующую библиотеку / класс, есть два способа запустить / отладить, 1-добавить ссылку на весь проект этогоnew
него, вариант 2 передать его в качестве параметра. Может быть не точным, но просто глупо легко понять.Внедрение зависимостей - это практика, при которой объекты проектируются таким образом, что они получают экземпляры объектов из других частей кода, а не конструируют их внутренне. Это означает, что любой объект, реализующий интерфейс, который требуется объекту, может быть заменен без изменения кода, что упрощает тестирование и улучшает развязку.
Например, рассмотрим эти предложения:
В этом примере реализации
PersonService::addManager
иPersonService::removeManager
потребуется экземпляр дляGroupMembershipService
того, чтобы выполнить свою работу. Без внедрения зависимостей традиционный способ сделать это - создать новый экземплярGroupMembershipService
в конструктореPersonService
и использовать этот атрибут экземпляра в обеих функциях. Однако, если конструкторGroupMembershipService
имеет несколько вещей, которые ему требуются, или, что еще хуже, есть некоторые «установщики» инициализации, которые необходимо вызыватьGroupMembershipService
, код растет довольно быстро, иPersonService
теперь это зависит не только от,GroupMembershipService
но и от всего остального, чтоGroupMembershipService
зависит от. Кроме того, связь сGroupMembershipService
жестко закодирована в,PersonService
что означает, что вы не можете "пустить в тупик"GroupMembershipService
для тестирования или для использования шаблона стратегии в различных частях вашего приложения.С внедрением Dependency Injection вместо создания экземпляра
GroupMembershipService
внутри вашегоPersonService
вы бы либо передали егоPersonService
конструктору, либо добавили свойство (getter и setter), чтобы установить его локальный экземпляр. Это означает, что вамPersonService
больше не нужно беспокоиться о том, как создатьGroupMembershipService
, он просто принимает те, которые он получил, и работает с ними. Это также означает, что все, что является подклассомGroupMembershipService
или реализуетGroupMembershipService
интерфейс, может быть « внедрено » вPersonService
, иPersonService
не нужно знать об изменениях.источник
Принятый ответ - хороший, но я хотел бы добавить к этому, что DI очень похож на классический отказ от жестко закодированных констант в коде.
Когда вы используете некоторую константу, такую как имя базы данных, вы быстро перемещаете ее изнутри кода в некоторый файл конфигурации и передаете переменную, содержащую это значение, в место, где оно необходимо. Причиной этого является то, что эти константы обычно меняются чаще, чем остальная часть кода. Например, если вы хотите проверить код в тестовой базе данных.
DI аналогичен этому в мире объектно-ориентированного программирования. Значения там вместо константных литералов являются целыми объектами - но причина удаления кода, создающего их, из кода класса аналогична - объекты меняются чаще, чем код, который их использует. Одним из важных случаев, когда необходимо такое изменение, являются тесты.
источник
Давайте попробуем простой пример с классами Car и Engine : любой автомобиль нуждается в двигателе, чтобы ехать куда угодно, по крайней мере, на данный момент. Ниже показано, как будет выглядеть код без внедрения зависимостей.
И чтобы создать экземпляр класса Car, мы будем использовать следующий код:
Проблема с этим кодом, которую мы тесно связали с GasEngine, и если мы решим изменить его на ElectricityEngine, то нам нужно будет переписать класс Car. И чем больше приложение, тем больше проблем и головной боли нам придется добавить и использовать новый тип движка.
Другими словами, при таком подходе наш класс автомобилей высокого уровня зависит от класса GasEngine более низкого уровня, который нарушает принцип инверсии зависимости (DIP) от SOLID. DIP предполагает, что мы должны зависеть от абстракций, а не от конкретных классов. Таким образом, чтобы удовлетворить это, мы вводим интерфейс IEngine и переписываем код, как показано ниже:
Теперь наш класс Car зависит только от интерфейса IEngine, а не от конкретной реализации движка. Теперь единственная хитрость заключается в том, как создать экземпляр Car и присвоить ему конкретный класс Engine, такой как GasEngine или ElectricityEngine. Вот где вводится зависимость .
Здесь мы в основном внедряем (передаем) нашу зависимость (экземпляр Engine) в конструктор Car. Так что теперь наши классы имеют слабую связь между объектами и их зависимостями, и мы можем легко добавлять новые типы двигателей без изменения класса Car.
Основное преимущество внедрения зависимостей заключается в том, что классы более слабо связаны, поскольку у них нет жестко закодированных зависимостей. Это следует принципу инверсии зависимости, который был упомянут выше. Вместо того, чтобы ссылаться на конкретные реализации, классы запрашивают абстракции (обычно интерфейсы ), которые предоставляются им при создании класса.
Также, когда у нас много зависимостей, очень хорошая практика - использовать контейнеры Inversion of Control (IoC), которые мы можем сказать, какие интерфейсы должны быть отображены, какие конкретные реализации для всех наших зависимостей, и мы можем разрешить им разрешить эти зависимости для нас при создании наш объект. Например, мы могли бы указать в сопоставлении для контейнера IoC, что зависимость IEngine должна быть сопоставлена с классом GasEngine, и когда мы запрашиваем у контейнера IoC экземпляр нашего класса Car , он автоматически создаст наш класс Car с помощью GasEngine. зависимостью прошло в.
ОБНОВЛЕНИЕ: Недавно посмотрел курс об EF Core от Джули Лерман, а также понравилось ее краткое определение о DI.
источник
Давайте представим, что вы хотите пойти на рыбалку:
Без внедрения зависимостей, вы должны позаботиться обо всем самостоятельно. Вам нужно найти лодку, купить рыболовную удочку, найти приманку и т. Д. Это, конечно, возможно, но это накладывает на вас большую ответственность. С точки зрения программного обеспечения это означает, что вы должны выполнить поиск всех этих вещей.
С инъекцией зависимости кто-то еще заботится обо всей подготовке и делает необходимое оборудование доступным для вас. Вы получите («впрысните») лодку, удочку и приманку - все готово к использованию.
источник
Это самое простое объяснение контейнера ввода зависимостей и зависимостей, которое я когда-либо видел:
Без внедрения зависимостей
С инъекцией зависимостей
Использование контейнера внедрения зависимостей
Dependency Injection и Dependency Injection Контейнеры разные вещи:
Вам не нужен контейнер для внедрения зависимостей. Однако контейнер может помочь вам.
источник
Разве «внедрение зависимостей» не означает просто использование параметризованных конструкторов и открытых сеттеров?
Статья Джеймса Шора показывает следующие примеры для сравнения .
источник
new DatabaseThingie()
не генерирует действительный экземпляр myDatabase.Сделать концепцию внедрения зависимостей простой для понимания. Давайте рассмотрим пример кнопки переключения для включения / выключения лампы.
Без внедрения зависимостей
Switch должен знать заранее, к какой лампочке я подключен (жестко запрограммированная зависимость). Так,
Switch -> PermanentBulb // переключатель напрямую подключен к постоянной лампе, тестирование невозможно
С инъекцией зависимостей
Коммутатор знает только, что мне нужно включить / выключить любую лампочку, которую мне передают. Так,
Переключатель -> Bulb1 ИЛИ Bulb2 ИЛИ NightBulb (введенная зависимость)
Модификация Джеймса для Switch и Bulb:
источник
Что такое инъекция зависимостей (DI)?
Как уже говорили другие, Dependency Injection (DI) устраняет ответственность за непосредственное создание и управление продолжительностью жизни других экземпляров объекта, от которых зависит наш класс интересов (потребительский класс) (в смысле UML ). Эти экземпляры вместо этого передаются в наш потребительский класс, как правило, в качестве параметров конструктора или через установщики свойств (управление экземпляром объекта зависимости и передачей в потребительский класс обычно выполняется с помощью Inversion of Control (IoC) контейнером , но это другая тема) ,
DI, DIP и SOLID
В частности, в парадигме SOLID принципов Роберта С. Мартина объектно-ориентированного проектирования ,
DI
является одной из возможных реализаций принципа инверсии зависимости (DIP) . DIP являетсяD
вSOLID
мантре - другие реализации DIP включают Service Locator, и паттерны Plugin.Целью DIP является разделение плотно, конкретные зависимости между классами, и вместо того , чтобы ослабить муфту с помощью абстракции, которые могут быть достигнуты с помощью
interface
,abstract class
илиpure virtual class
, в зависимости от используемого языка и подхода.Без DIP наш код (я назвал это «потребляющий класс») напрямую связан с конкретной зависимостью и также часто обременен обязанностью знать, как получить и управлять экземпляром этой зависимости, то есть концептуально:
Принимая во внимание, что после применения DIP требование ослабляется, и
Foo
устраняется проблема получения и управления сроком службы зависимости:Зачем использовать DIP (и DI)?
Разделение зависимостей между классами таким способом позволяет легко заменить эти классы зависимостей другими реализациями, которые также выполняют предварительные условия абстракции (например, зависимость может быть переключена с другой реализацией того же интерфейса). Кроме того, как уже упоминалось, возможно , , наиболее распространенной причиной для классов разъединить с помощью DIP, чтобы позволить потребляя класс для тестирования в изоляции, так как эти же зависимостей теперь могут быть загасил и / или издевались.
Одним из следствий DI является то, что управление временем жизни экземпляров объекта зависимости больше не контролируется потребляющим классом, так как объект зависимости теперь передается в потребляющий класс (через внедрение конструктора или сеттера).
Это можно посмотреть по-разному:
Create
фабрику по мере необходимости и утилизировать эти экземпляры после завершения.Когда использовать DI?
MyDepClass
это потокобезопасность?пример
Вот простая реализация C #. Учитывая ниже класс потребления:
Несмотря на то, что он выглядит безобидным, он имеет две
static
зависимости от двух других классовSystem.DateTime
иSystem.Console
, который не только ограничивает параметры вывода журналов (вход в консоль будет бесполезным, если никто не наблюдает), но, что еще хуже, автоматическое тестирование с учетом зависимости от этого затруднительно недетерминированные системные часы.Однако мы можем применить
DIP
к этому классу, абстрагируясь от того, что временные метки являются зависимостями и связаныMyLogger
только с простым интерфейсом:Мы также можем ослабить зависимость от
Console
абстракции, такой какTextWriter
. Внедрение зависимостей обычно реализуется либо какconstructor
внедрение (передача абстракции зависимости в качестве параметра конструктору потребляющего класса), либоSetter Injection
(передача зависимости черезsetXyz()
установщик или свойство .Net с{set;}
заданным значением). Внедрение в конструктор является предпочтительным, поскольку это гарантирует, что класс будет в правильном состоянии после создания, и позволяет полям внутренней зависимости помечаться какreadonly
(C #) илиfinal
(Java). Таким образом, используя инъекцию конструктора в приведенном выше примере, мы получаем:(Необходимо предоставить конкретную
Clock
информацию, к которой, конечно, можно вернутьсяDateTime.Now
, и две зависимости должны быть предоставлены контейнером IoC посредством внедрения конструктора)Может быть построен автоматический модульный тест, который однозначно доказывает, что наш регистратор работает правильно, поскольку теперь у нас есть контроль над зависимостями - временем, и мы можем следить за записанным выводом:
Следующие шаги
Внедрение зависимостей неизменно связано с контейнером инверсии (IoC) , чтобы внедрить (предоставить) конкретные экземпляры зависимостей и управлять экземплярами продолжительности жизни. В процессе конфигурирования / начальной загрузки
IoC
контейнеры позволяют определять следующее:IBar
, возвращаетConcreteBar
экземпляр» )IDisposable
и будут нести ответственность заDisposing
зависимости в соответствии с настроенным управлением продолжительностью жизни.Как правило, после настройки / загрузки контейнеров IoC они работают в фоновом режиме, позволяя кодеру сосредоточиться на имеющемся коде, а не беспокоиться о зависимостях.
Как в приведенном выше примере, разделение зависимостей требует определенных усилий по проектированию, и для разработчика существует смена парадигмы, необходимая для того, чтобы избавиться от привычки
new
напрямую зависеть от зависимостей и вместо этого доверять контейнеру управление зависимостями.Но преимуществ много, особенно в том, что касается возможности тщательно проверить свой класс интересов.
Примечание . Создание / отображение / проекция (через
new ..()
) POCO / POJO / Сериализация DTO / Графы сущностей / Анонимные проекции JSON и др., Т.е. классы или записи «Только данные», используемые или возвращаемые из методов, не рассматриваются как зависимости (в Смысл UML) и не подлежит DI. Использованиеnew
для проецирования это просто отлично.источник
Смысл Dependency Injection (DI) в том, чтобы поддерживать исходный код приложения в чистоте и стабильности :
Практически, каждый шаблон проектирования разделяет проблемы, чтобы будущие изменения повлияли на минимум файлов.
Конкретной областью DI является делегирование конфигурации и инициализации зависимостей.
Пример: DI со сценарием оболочки
Если вы время от времени работаете за пределами Java, вспомните, как
source
это часто используется во многих языках сценариев (Shell, Tcl и т. Д. Или дажеimport
в Python, неправильно используемых для этой цели).Рассмотрим простой
dependent.sh
скрипт:Сценарий является зависимым: он не будет успешно выполнен самостоятельно (
archive_files
не определен).Вы определяете
archive_files
вarchive_files_zip.sh
скрипте реализации (используяzip
в этом случае):Вместо
source
-ing сценария реализации непосредственно в зависимом, вы используетеinjector.sh
«контейнер», который оборачивает оба «компонента»:archive_files
Зависимость только что была введена в зависимый сценарий.Вы могли бы ввести зависимость, которая реализует
archive_files
использованиеtar
илиxz
.Пример: удаление DI
Если
dependent.sh
скрипт использует зависимости напрямую, этот подход будет называться поиском зависимостей (что противоположно внедрению зависимостей ):Теперь проблема в том, что зависимый «компонент» должен выполнить инициализацию самостоятельно.
Исходный код «компонента» не является ни чистым, ни стабильным, потому что каждое изменение в инициализации зависимостей требует новой версии и для файла исходного кода «компонентов».
Последние слова
DI не так сильно подчеркивается и популяризируется, как в Java-фреймворках.
Но это общий подход для разделения проблем:
Использование конфигурации только с поиском зависимостей не помогает, так как количество параметров конфигурации может изменяться для каждой зависимости (например, новый тип аутентификации), а также количество поддерживаемых типов зависимостей (например, новый тип базы данных).
источник
Все вышеприведенные ответы хороши, моя цель - объяснить концепцию простым способом, чтобы любой, кто не обладает знаниями в области программирования, также мог понять концепцию.
Внедрение зависимостей является одним из шаблонов проектирования, который помогает нам создавать сложные системы более простым способом.
Мы можем видеть широкое применение этого шаблона в нашей повседневной жизни. Некоторые из примеров: магнитофон, VCD, CD-привод и т. Д.
Это изображение представляет собой портативный магнитофон Reel-to-reel, середина 20-го века. Источник .
Основным назначением магнитофона является запись или воспроизведение звука.
При проектировании системы требуется катушка для записи или воспроизведения звука или музыки. Есть две возможности для проектирования этой системы
Если мы используем первый, нам нужно открыть машину, чтобы сменить катушку. если мы выберем второй вариант, который устанавливает крючок для барабана, мы получаем дополнительное преимущество от воспроизведения любой музыки, меняя барабан. а также уменьшая функцию только для воспроизведения чего-либо на барабане.
Подобным образом, внедрение зависимостей - это процесс извлечения зависимостей, чтобы сосредоточиться только на конкретной функциональности компонента, чтобы независимые компоненты могли быть соединены вместе, чтобы сформировать сложную систему.
Основные преимущества мы достигли с помощью внедрения зависимостей.
В наши дни эта концепция лежит в основе известных фреймворков в мире программирования. Spring Angular и т. Д. - это хорошо известные программные среды, построенные на основе этой концепции.
Внедрение зависимостей - это шаблон, используемый для создания экземпляров объектов, на которые полагаются другие объекты, не зная во время компиляции, какой класс будет использоваться для предоставления этих функций, или просто способ внедрения свойств в объект называется инъекцией зависимости.
Пример для внедрения зависимости
Ранее мы пишем такой код
С внедрением Dependency инжектор зависимостей снимает для нас экземпляр
Вы также можете прочитать
Разница между инверсией контроля и инъекцией зависимостей
источник
Что такое инъекция зависимости?
Внедрение зависимостей (DI) означает разделение объектов, которые зависят друг от друга. Скажем, объект A зависит от объекта B, поэтому идея состоит в том, чтобы отделить эти объекты друг от друга. Нам не нужно жестко кодировать объект с использованием нового ключевого слова, а делиться зависимостями с объектами во время выполнения, несмотря на время компиляции. Если мы говорим о
Как работает Dependency Injection весной:
Нам не нужно жестко кодировать объект, используя ключевое слово new, а определить зависимость bean-компонента в файле конфигурации. Пружинный контейнер будет отвечать за подключение всех.
Инверсия Контроля (МОК)
МОК является общей концепцией, и ее можно выразить многими различными способами, а внедрение зависимости является одним из конкретных примеров МОК.
Два типа внедрения зависимостей:
1. Конструкторское внедрение зависимостей:
DI на основе конструктора выполняется, когда контейнер вызывает конструктор класса с несколькими аргументами, каждый из которых представляет зависимость от другого класса.
2. Установка зависимости на основе установки:
DI на основе установки выполняется контейнером, вызывающим методы setter для ваших bean-компонентов после вызова конструктора без аргументов или статического метода фабрики без аргументов для создания экземпляра вашего bean-компонента.
ПРИМЕЧАНИЕ. Хорошее практическое правило - использовать аргументы конструктора для обязательных зависимостей и методы установки для необязательных зависимостей. Обратите внимание, что если мы используем аннотацию на основе, то аннотацию @Required для установщика можно использовать для создания сеттеров в качестве необходимых зависимостей.
источник
Лучшая аналогия, которую я могу придумать, - это хирург и его ассистент (ы) в операционном зале, где хирург является основным человеком и его ассистентом, который предоставляет различные хирургические компоненты, когда ему это нужно, чтобы хирург мог сосредоточиться на одном. что он делает лучше всего (операция). Без ассистента хирург должен сам получать компоненты каждый раз, когда он ему нужен.
DI для краткости - это метод, позволяющий снять общую дополнительную ответственность (нагрузку) с компонентов за выборку зависимых компонентов, предоставляя их им.
DI приближает вас к принципу единой ответственности (SR), например
surgeon who can concentrate on surgery
.Когда использовать DI: Я бы рекомендовал использовать DI практически во всех производственных проектах (малых / больших), особенно в постоянно меняющихся бизнес-средах :)
Почему: потому что вы хотите, чтобы ваш код был легко тестируемым, макетируемым и т. Д., Чтобы вы могли быстро протестировать свои изменения и вывести их на рынок. Кроме того, почему бы вам этого не сделать, когда у вас есть множество отличных бесплатных инструментов / фреймворков, которые помогут вам в вашем путешествии к базе кода, где у вас больше контроля.
источник
Например, у нас есть 2 класса
Client
иService
.Client
буду использоватьService
Без внедрения зависимостей
Способ 1)
Способ 2)
Способ 3)
1) 2) 3) Использование
преимущества
Недостатки
Client
классаService
конструктор, нам нужно изменить код во всем месте созданияService
объектаИспользовать инъекцию зависимостей
Способ 1) Конструктор впрыска
С помощью
Способ 2) Сеттер впрыска
С помощью
Способ 3) Внедрение интерфейса
Проверьте https://en.wikipedia.org/wiki/Dependency_injection
===
Теперь этот код уже соблюдается,
Dependency Injection
и он легче для тестовогоClient
класса.Тем не менее, мы все еще используем
new Service()
много времени, и это не очень хорошо, когда меняемService
конструктор. Чтобы предотвратить это, мы можем использовать DI инжектор, как1) Простое руководство
Injector
С помощью
2) Использование библиотеки: для Android dagger2
преимущества
Service
, вам нужно только изменить его в классе инжекторовConstructor Injection
, когда вы посмотрите на конструктор ofClient
, вы увидите, сколько зависимостейClient
классаНедостатки
Constructor Injection
,Service
объект создается приClient
создании, иногда мы используем функцию вClient
классе без использования,Service
поэтому созданный объектService
теряетсяОпределение внедрения зависимости
https://en.wikipedia.org/wiki/Dependency_injection
источник
Это означает, что у объектов должно быть столько зависимостей, сколько необходимо для их работы, а зависимостей должно быть немного. Кроме того, зависимости объекта должны быть по интерфейсам, а не по «конкретным» объектам, когда это возможно. (Конкретный объект - это любой объект, созданный с помощью ключевого слова new.) Слабая связь способствует большей возможности повторного использования, облегчает обслуживание и позволяет легко предоставлять «фиктивные» объекты вместо дорогих услуг.
«Инъекция зависимости» (DI) также известна как «Инверсия контроля» (IoC) и может использоваться в качестве метода для поощрения этой слабой связи.
Существует два основных подхода к реализации DI:
Конструктор инъекций
Это техника передачи зависимостей объекта его конструктору.
Обратите внимание, что конструктор принимает интерфейс, а не конкретный объект. Также обратите внимание, что возникает исключение, если параметр orderDao имеет значение null. Это подчеркивает важность получения действительной зависимости. Инжектор конструктора, на мой взгляд, является предпочтительным механизмом предоставления объекту его зависимостей. При вызове объекта для разработчика ясно, какие зависимости необходимо передать объекту «Person» для правильного выполнения.
Сеттер Инъекция
Но рассмотрим следующий пример ... Предположим, у вас есть класс с десятью методами, которые не имеют зависимостей, но вы добавляете новый метод, который имеет зависимость от IDAO. Вы можете изменить конструктор, чтобы использовать конструктор Injection, но это может заставить вас вносить изменения во все вызовы конструктора повсюду. В качестве альтернативы, вы можете просто добавить новый конструктор, который получает зависимость, но тогда как разработчик легко узнает, когда использовать один конструктор над другим. Наконец, если создать зависимость очень дорого, зачем ее создавать и передавать конструктору, если ее можно использовать редко? «Инъекция сеттера» - это еще один метод DI, который можно использовать в таких ситуациях, как эта.
Внедрение сеттера не заставляет зависимости передаваться в конструктор. Вместо этого зависимости устанавливаются на общедоступные свойства, предоставляемые нуждающимся объектом. Как подразумевалось ранее, основными мотиваторами для этого являются:
Вот пример того, как будет выглядеть приведенный выше код:
источник
Я думаю, так как все написали для DI, позвольте мне задать несколько вопросов ..
Это основано на ответе @ Adam N опубликовано.
Почему PersonService больше не нужно беспокоиться о GroupMembershipService? Вы только что упомянули, что GroupMembership имеет несколько вещей (объектов / свойств), от которых зависит. Если в PService требуется GMService, он будет иметь свойство. Вы можете сделать это вне зависимости от того, вводили вы это или нет. Единственный раз, когда я хотел бы, чтобы его вводили, - это если бы в GMService были более конкретные дочерние классы, которые вы не знали бы до времени выполнения. Тогда вы захотите внедрить подкласс. Или, если вы хотите использовать это как синглтон или прототип. Честно говоря, в файле конфигурации есть все, что жестко запрограммировано в том, что касается подкласса для типа (интерфейса), который он собирается внедрить во время компиляции.
РЕДАКТИРОВАТЬ
Хороший комментарий Хосе Мария Арранц на DI
DI повышает сплоченность, устраняя необходимость определять направление зависимости и писать любой связующий код.
Ложь. Направление зависимостей находится в форме XML или в виде аннотаций, ваши зависимости записываются в виде XML-кода и аннотаций. XML и аннотации являются исходным кодом.
DI уменьшает связь, делая все ваши компоненты модульными (т.е. заменяемыми) и имеет четко определенные интерфейсы друг с другом.
Ложь. Вам не нужна структура DI для построения модульного кода на основе интерфейсов.
О заменяемых: с очень простым архивом .properties и Class.forName вы можете определить, какие классы можно изменить. Если ЛЮБОЙ класс вашего кода можно изменить, Java не для вас, используйте язык сценариев. Кстати, аннотации нельзя изменить без перекомпиляции.
По моему мнению, есть одна единственная причина для каркасов DI: уменьшение котельной плиты. С хорошо сделанной фабричной системой вы можете сделать то же самое, более управляемое и более предсказуемое, что и предпочитаемая вами DI-среда, DI-структуры обещают сокращение кода (XML и аннотации также являются исходным кодом). Проблема заключается в том, что это сокращение базовой платы просто реально в очень очень простых случаях (один экземпляр на класс и аналогичные), иногда в реальном мире выбор подходящего объекта обслуживания не так прост, как сопоставление класса с одноэлементным объектом.
источник
Популярные ответы бесполезны, потому что они определяют внедрение зависимостей таким образом, что это бесполезно. Давайте согласимся, что под «зависимостью» мы подразумеваем некоторый ранее существующий другой объект, который нужен нашему объекту X. Но мы не говорим, что делаем «внедрение зависимости», когда говорим
Мы просто называем это передачей параметров в конструктор. Мы занимаемся этим регулярно с тех пор, как были изобретены конструкторы.
«Внедрение зависимостей» считается типом «инверсии управления», что означает, что некоторая логика удалена из вызывающей стороны. Это не тот случай, когда вызывающая сторона передает параметры, поэтому, если бы это был DI, DI не означало бы инверсию управления.
DI означает, что существует промежуточный уровень между вызывающей стороной и конструктором, который управляет зависимостями. Makefile - простой пример внедрения зависимостей. «Вызывающий» - это человек, набирающий «make bar» в командной строке, а «constructor» - это компилятор. Makefile указывает, что bar зависит от foo, и делает
прежде чем делать
Человеку, печатающему «make bar», не обязательно знать, что bar зависит от foo. Зависимость была введена между "make bar" и gcc.
Основная цель промежуточного уровня - не просто передать зависимости конструктору, но перечислить все зависимости в одном месте. и спрятать их от кодера (чтобы кодер не предоставлял их).
Обычно промежуточный уровень предоставляет фабрики для созданных объектов, которые должны обеспечивать роль, которой должен удовлетворять каждый запрашиваемый тип объекта. Это потому, что имея промежуточный уровень, который скрывает детали конструкции, вы уже понесли штраф за абстракцию, наложенный фабриками, так что вы также можете использовать фабрики.
источник
Инъекция зависимостей означает путь (фактически любой ) для одной части кода (например, класса) иметь доступ к зависимостям (другим частям кода, например, другим классам, от которых это зависит) модульным способом без их жесткого кодирования (поэтому они могут быть изменены или могут быть переопределены свободно, или даже могут быть загружены в другое время, если это необходимо)
(и ps, да, это стало чрезмерно раскрученным названием за 25 $ для довольно простой, концепции) , мои
.25
центыисточник
Я знаю, что ответов уже много, но я нашел это очень полезным: http://tutorials.jenkov.com/dependency-injection/index.html
Нет зависимости:
Зависимость:
Обратите внимание, как
DataSourceImpl
экземпляр перемещается в конструктор. Конструктор принимает четыре параметра, которые являются четырьмя значениями, необходимыми дляDataSourceImpl
. ХотяMyDao
класс все еще зависит от этих четырех значений, он сам больше не удовлетворяет этим зависимостям. Они предоставляются любым классом, создающимMyDao
экземпляр.источник
Инъекция зависимости является одним из возможных решений того, что обычно называют требованием «обфускации зависимости». Запутывание зависимостей - это метод, позволяющий исключить «очевидную» природу из процесса предоставления зависимости классу, который требует ее, и, следовательно, каким-то образом запутывать предоставление указанной зависимости указанному классу. Это не обязательно плохо. Фактически, запутывая способ предоставления зависимости классу, что-то за пределами класса отвечает за создание зависимости, что означает, что в различных сценариях может быть предоставлена другая реализация зависимости без внесения каких-либо изменений. к классу. Это отлично подходит для переключения между рабочим и тестовым режимами (например, с использованием «фиктивной» зависимости сервиса).
К сожалению, плохая часть заключается в том, что некоторые люди предполагают, что вам нужна специализированная среда для обфускации зависимостей, и что вы как-то «меньший» программист, если решите не использовать конкретную среду для этого. Еще один, крайне тревожный миф, по мнению многих, заключается в том, что внедрение зависимости является единственным способом достижения запутывания зависимости. Это наглядно и исторически, и, очевидно, на 100% неправильно, но у вас будут проблемы с убеждением некоторых людей, что существуют альтернативы внедрению зависимости для ваших требований обфускации зависимости.
Программисты понимали требование запутывания зависимостей в течение многих лет, и многие альтернативные решения развивались как до, так и после зачатия зависимости. Существуют фабричные шаблоны, но есть также много опций, использующих ThreadLocal, где не требуется внедрение в конкретный экземпляр - зависимость эффективно внедряется в поток, что дает преимущество в том, что объект становится доступным (с помощью удобных статических методов получения) для любогокласс, который требует этого без необходимости добавлять аннотации к классам, которые этого требуют, и настраивать сложный XML-клей, чтобы это произошло. Когда ваши зависимости требуются для персистентности (JPA / JDO и т. Д.), Это позволяет вам гораздо легче достичь «прозрачной персистентности», а классы предметной модели и бизнес-модели состоят исключительно из POJO (то есть, нет специфичной для фреймворка / заблокированной в аннотациях).
источник
Из книги « Обоснованный Java-разработчик: жизненно важные методы Java 7 и программирование полиглотов»
источник
Прежде чем перейти к техническому описанию, сначала визуализируйте его на примере из реальной жизни, потому что вы найдете много технических вещей для изучения внедрения зависимостей, но максимальное количество времени такие люди, как я, не могут понять основную концепцию этого.
На первом рисунке предположим, что у вас есть автомобильный завод с множеством объединений. Автомобиль на самом деле встроен в сборочную единицу, но ему нужны двигатель , сиденья и колеса . Таким образом, сборочная единица зависит от этих всех узлов, и они являются зависимостями завода.
Вы можете почувствовать, что теперь слишком сложно поддерживать все задачи на этом заводе, потому что наряду с основной задачей (Сборка автомобиля в сборочном блоке) вам также необходимо сосредоточиться на других устройствах . В настоящее время его обслуживание обходится очень дорого, а здание фабрики огромно, поэтому за аренду требуются дополнительные деньги.
Теперь посмотрим на вторую картинку. Если вы найдете компании-поставщики, которые предоставят вам колеса , сиденья и двигатель дешевле, чем ваши расходы на самостоятельное производство, то теперь вам не нужно делать их на своем заводе. Вы можете арендовать меньшее здание сейчас только для вашей сборочной единицы, что уменьшит ваши задачи по обслуживанию и уменьшит ваши дополнительные расходы на аренду. Теперь вы также можете сосредоточиться только на своей основной задаче (сборка автомобиля).
Теперь можно сказать, что все зависимости для сборки автомобиля внедряются на заводе от поставщиков . Это пример реальной инъекции зависимости (DI) .
Теперь, с технической точки зрения, внедрение зависимостей - это метод, при котором один объект (или статический метод) предоставляет зависимости другого объекта. Таким образом, передача задачи создания объекта кому-либо и непосредственного использования зависимости называется внедрением зависимости.
Это поможет вам теперь изучить DI с помощью нескольких слов. Это покажет, когда использовать DI, а когда нет .
,
источник
из книги Apress.Spring.Persistence.with.Hibernate.Oct.2010
источник
Внедрение зависимостей (DI) является одним из шаблонов проектирования, в котором используется основная функция ООП - связь в одном объекте с другим объектом. В то время как наследование наследует один объект, чтобы сделать более сложный и конкретный другой объект, связь или ассоциация просто создает указатель на другой объект из одного объекта с использованием атрибута. Мощность DI сочетается с другими функциями ООП, такими как интерфейсы и скрытый код. Предположим, у нас есть клиент (подписчик) в библиотеке, который может для простоты заимствовать только одну книгу.
Интерфейс книги:
Далее у нас может быть много разных книг; один из типов это фантастика:
Теперь подписчик может иметь ассоциацию с книгой:
Все три класса могут быть скрыты для собственной реализации. Теперь мы можем использовать этот код для DI:
Есть много разных способов использования внедрения зависимостей. Можно комбинировать его с Singleton и т. Д., Но в основном это только ассоциация, реализованная путем создания атрибута типа объекта внутри другого объекта. Полезность только и только в том, что код, который мы должны писать снова и снова, всегда готов и сделан для нас вперед. Вот почему DI так тесно связан с Inversion of Control (IoC), что означает, что наша программа передает управление другому работающему модулю, который делает инъекции bean-компонентов в наш код. (Каждый объект, который может быть введен, может быть подписан или рассматриваться как Бин.) Например, в Spring это делается путем создания и инициализации. ApplicationContext.контейнер, который делает эту работу для нас. Мы просто в нашем коде создаем Context и вызываем инициализацию bean-компонентов. В этот момент инъекция была сделана автоматически.
источник
Инъекция зависимости для 5 лет.
Когда вы идете и достаете вещи из холодильника для себя, у вас могут возникнуть проблемы. Вы можете оставить дверь открытой, вы можете получить что-то, что мама или папа не хотят, чтобы вы имели. Возможно, вы даже ищете что-то, чего у нас нет или срок действия которого истек.
То, что вы должны делать, это заявить о необходимости: «Мне нужно что-нибудь выпить с обедом», и тогда мы позаботимся о том, чтобы у вас было что-нибудь, когда вы сядете поесть.
источник
Из книги Кристоффера Норинга, книги Пабло Дилемана «Углубленное изучение - второе издание»:
«По мере роста и развития наших приложений каждому из наших объектов кода будут внутренне требовать экземпляры других объектов , которые более известны как зависимости в мире разработки программного обеспечения. Действие передачи таких зависимостей зависимому клиенту известно как внедрение , и это также влечет за собой участие другого объекта кода, названного инжектором . Инжектор будет нести ответственность за создание и запуск требуемого зависимостейпоэтому они готовы к использованию с того самого момента, как они успешно введены в клиент. Это очень важно, поскольку клиент ничего не знает о том, как создавать свои собственные зависимости, и знает только об интерфейсе. они реализуют, чтобы использовать их ».
От: Антон Моисеев. книга «Угловое развитие с Typescript, второе издание».
«Короче говоря, DI помогает вам писать код в слабосвязанной форме и делает ваш код более тестируемым и пригодным для повторного использования ».
источник
Проще говоря, внедрение зависимостей (DI) - это способ удалить зависимости или тесную связь между различными объектами. Инъекция зависимостей дает связное поведение каждому объекту.
DI - это реализация принципала Spring в МОК, который гласит: «Не звоните нам, мы вам позвоним». При использовании инжекции зависимостей программисту не нужно создавать объект, используя ключевое слово new.
Объекты однажды загружаются в контейнер Spring, а затем мы используем их всякий раз, когда они нам нужны, выбирая эти объекты из контейнера Spring с помощью метода getBean (String beanName).
источник
Внедрение зависимостей является сердцем концепции, связанной с Spring Framework. При создании каркаса любого проекта Spring может играть жизненно важную роль, и здесь внедрение зависимостей приходит в кувшин.
На самом деле, предположим, что в Java вы создали два разных класса, как класс A и класс B, и любую функцию, доступную в классе B, которую вы хотите использовать в классе A, так что в этот момент можно использовать внедрение зависимостей. где вы можете создать объект одного класса в другом, таким же образом вы можете внедрить целый класс в другой класс, чтобы сделать его доступным. таким образом, зависимость может быть преодолена.
ЗАВИСИМОСТЬ ОТ ЗАВИСИМОСТИ ПРОСТО СКЛЕИВАЯ ДВУХ КЛАССОВ И ОДНОВРЕМЕННО СОХРАНЯЯ ИХ.
источник