Краткое введение во внедрение зависимостей: что это и когда это необходимо использовать
Вольный перевод статьи Bhavya Karia: A quick intro to Dependency Injection: what it is, and when to use it.
Введение
В разработке программного обеспечения, внедрение зависимостей это такая техника, где посредством одного объекта (или статического метода) предоставляются зависимости другого объекта. Зависимость — это объект, который может быть использован (как сервис).
Это определение из Википедии (в версии на английском языке — прим. переводчика), и все же, его не так и просто понять. Давайте разберемся с этим получше.
Перед тем как понять, что же это означает в программировании, давайте сначала разберемся, что это означает в общем смысле. Таким образом это поможет нам лучше разобраться с этим понятием.
Зависимость или зависимое — означает полагаться на что-то. Это все равно что, если сказать, что мы слишком много полагаемся на мобильные телефоны — это означает, что мы зависим от них.
Поэтому, прежде чем перейти к понятию внедрение зависимостей, сначала давайте разберемся, что означает зависимость в программировании.
Когда класс A использует некоторую функциональность из класса B, тогда говорят, что класс A зависим от класса B.
В Java, прежде чем мы сможем использовать методы других классов, нам необходимо для начала создать экземпляры этого класса (то есть класс А должен создать экземпляр класса В).
Таким образом, передавая задачу создания объекта чему-то другому и прямое использование этой зависимости называется внедрением зависимостей.
Так почему следует использовать внедрение зависимостей?
Представьте, что у нас есть класс для описания автомобилей, также содержащий другие различные объекты, например, колеса, двигатели и прочее.
Перед вами класс Car, отвечающий за создание всех объектов зависимостей. Теперь, что если мы решим избавиться колес компании MRFWheels и хотим использовать колеса от Yokohama в будущем?
Нам нужно будет воссоздать объект класса Car с новой зависимостью от Yokohama. Но при использовании внедрении зависимостей мы можем изменить колеса во время выполнения программы (потому что зависимости можно внедрять во время выполнения, а не во время компиляции).
Вы можете думать о внедрении зависимостей как о посреднике в нашем коде, который выполняет всю работу по созданию предпочтительного объекта колеса и предоставлению его классу Автомобиль.
Это делает наш класс автомобилей независимым от создания объектов таких как колеса, аккумулятор и т.д.
Существует три основных типа внедрения зависимостей:
- constructor injection: все зависимости передаются через конструктор класса.
- setter injection: разработчик добавляет setter-метод, с помощью которого инжектор внедряет зависимость
- interface injection: зависимость предоставляет инжектору метод, с помощью которого инжектор передаст зависимость. Разработчики должны реализовать интерфейс, предоставляющий setter-метод, который принимает зависимости
Внедрение зависимостей ответственно за:
- Создание объектов;
- Представление о том, какие классы требуются этим объектам;
- И предоставление зависимостей этим объектам.
Если есть какие-либо изменения в объектах, то DI смотрит на него, и он не должен относиться к классу с использованием этих объектов.
Таким образом, если объекты будут меняться в будущем, тогда ответственность DI заключается в предоставлении соответствующих объектов классу.
Инверсия управления — концепция, лежащая в основе внедрения зависимости
Это означает, что класс не должен конфигурировать свои зависимости статистически, а должен быть сконфигурирован другим классом извне.
Это пятый принцип S.O.L.I.D из пяти основных принципов объектно-ориентированного программирования и разработки от дяди Боба, в котором говорится, что класс должен зависеть от абстракции, а не от чего-то конкретного (простыми словами, жестко закодированного).
Согласно принципам, класс должен полностью сосредоточиться на выполнении своих обязанностей, а не на создании объектов, необходимых для выполнения этих обязанностей. И именно здесь начинается внедрение зависимостей: она предоставляет классу требуемые объекты.
Замечание: Если вы хотите узнать больше о принципах SOLID от дяди Боба вы можете перейти по этой ссылке.
Преимущества использования внедрения зависимостей
- Помогает в модульном тестировании
- Количество шаблонного кода сокращается, поскольку инициализация зависимостей выполняется компонентом инжектора;
- Расширение приложения становится еще проще;
- Помогает уменьшить связность кода, что важно при разработке приложений.
Недостатки использования внедрения зависимостей
- Это несколько сложновато для изучения, а чрезмерное использование может привести к проблемам управления или другим проблемам.
- Многие возможные ошибки из процесса компиляции перемещаются в процесс выполнения программы.
- Внедрения зависимостей во фреймворках реализовано с помощью рефлексии или динамического программирования. Это может помешать использованию автоматизации разработки с помощью IDE, например, будет сложно воспользоваться функциями «найти ссылки», «показать иерархию вызовов» и будет сложно заниматься безопасно рефакторингом.
Тем не менее вы вполне можете реализовать внедрение зависимостей самостоятельно без использования сторонних библиотек и фреймворков или используя их.
Библиотеки и фреймворки, реализующие внедрение зависимостей
- Spring (Java)
- Google Guice (Java)
- http://square.github.io/dagger/ (Java and Android)
- Castle Windsor (.NET)
- Unity(.NET)
Для того чтобы узнать больше о внедрении зависимостей, вы можете ознакомиться со списком дополнительных источников ниже:
- Java Dependency Injection — DI Design Pattern Example Tutorial — JournalDev
- Using dependency injection in Java — Introduction — Tutorial — Vogella
- Inversion of Control Containers and the Dependency Injection pattern — Martin Fowler
Надеюсь, это вам помогло!