Определение, принципы и использование этого метода программирования

Внедрение зависимостей было представлено Мартином Фаулером в блоге Инверсия контейнеров управления и шаблон внедрения зависимостей. Основная цель состоит в том, чтобы отделить ответственность за разрешение зависимости объекта от его поведения.

Определение

Внедрение зависимостей (DI) — это метод программирования, который делает класс независимым от его зависимостей.

«В программной инженерии внедрение зависимостей — это метод, при котором один объект предоставляет зависимости другому объекту. «Зависимость» — это объект, который можно использовать, например, в качестве службы. Вместо того, чтобы клиент указывал, какую службу он будет использовать, что-то сообщает клиенту, какую службу использовать. «Инъекция» относится к передаче зависимости (службы) объекту (клиенту), который будет ее использовать. Сервис сделан частью состояния клиента. Передача службы клиенту, а не предоставление клиенту возможности создать или найти службу, является фундаментальным требованием шаблона». Источник: Википедия

Создание объектов непосредственно внутри класса негибко, потому что оно связывает класс с конкретными объектами и делает невозможным изменение экземпляра позже независимо от класса. Это препятствует повторному использованию класса, если требуются другие объекты, и затрудняет тестирование класса, поскольку реальные объекты нельзя заменить фиктивными объектами.

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

Разделение ответственности

  • DI предполагает, что тесная связь реализации объектов — это плохо.
  • DI предполагает, что зависимый класс никогда не является подходящим местом для создания зависимости.
  • DI по своей природе централизует знания обо всех зависимостях и их реализациях.

Жесткая связь и слабая связь

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

Инверсия управления (IoC), инверсия зависимостей

Принцип (DIP) и внедрение зависимостей (DI)

Инверсия управления (IoC) — это принцип проектирования, используемый для инвертирования различных видов элементов управления в объектно-ориентированном проектировании для достижения слабой связи.

Принцип инверсии зависимостей (DIP) гласит, что модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракции.
Абстракции не должны зависеть от деталей, должны зависеть от абстракций.

Внедрение зависимостей (DI) — это шаблон проектирования, используемый для реализации IoC.

Контейнер IoC

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

Контейнер создает объект указанного класса, а также внедряет все объекты зависимостей через конструктор, свойство или метод во время выполнения и удаляет их в соответствующее время. Это сделано для того, чтобы нам не приходилось создавать объекты и управлять ими вручную.
Контейнеры обеспечивают поддержку следующего жизненного цикла внедрения зависимостей.

  • Регистрация. Определяет, экземпляр какой зависимости создавать при обнаружении определенного типа.
  • Решение: нам не нужно создавать объекты вручную. Контейнер делает это за нас. Контейнер включает в себя несколько методов для разрешения указанного типа и создает объект указанного типа, внедряет необходимые зависимости и возвращает объект.
  • Dispose: управляет временем существования зависимых объектов.

Срок службы

Срок службы означает, как долго услуга будет жить, прежде чем она будет утилизирована. В настоящее время существует три разных срока службы:

  • Переходный. Служба создается каждый раз, когда ее запрашивают.
  • Singleton: создается один раз на весь срок службы приложения.
  • С областью действия: создается один раз для каждого запроса.

Примеры контейнеров:
StructureMap
Unity
Ninject
Autofact
.Net Core Container

Пример реализации с .NET Core

Это простой пример, показывающий, как вы регистрируете и разрешаете зависимости с помощью метода внедрения зависимостей в .NET Core.

Цель состоит в том, чтобы предоставить веб-API, который получает список альбомов, использующих Сервис.

Создайте новую библиотеку классов с именем Services и новый класс для представления альбома.

Создать альбом класса:

namespace Services.Entities
{
8 references
public class Album
{
3 references
public string Name { get; set; }
3 references
public string ArtistName { get; set; }
}
}

Определите операции, которые необходимо реализовать:

namespace Services.Interfaces
{
4 references
public interface IAlbumService
{
2 references
IEnumerable GetAlbums ();
}
}

Создайте класс для реализации IAlbumService:

namespace Services
{
1 reference
public class AlbumService : IAlbumService
{
private readonly List _albums = new List()
{
new Album { Name= "Battle of Los Angeles", ArtistName="Rage Against the Machine" },
new Album { Name= "Cowboys from Hell", ArtistName="Pantera" },
new Album { Name= "Black Album", ArtistName="Metalica" },
};
2 references
public IEnumerable GetAlbums()
{
return _albuns.AsEnumerable();
}
}
}

Создайте новый проект WebAPI и зарегистрируйте зависимости

Во-первых, мы должны установить пакет Microsoft.Extensions.DependencyInjection с помощью Nuget.

Точкой входа веб-API является файл Startup.cs. Зарегистрируем зависимость от ConfigureService:

public void ConfigureServices(сервисы IServiceCollection)
{
services.AddTransient();
}

Добавьте новый альбом контроллера с помощью метода Get, чтобы вернуть список альбомов. Зависимость будет внедрена конструктором.

namespace Api.Controllers
{
[Route(template:"api/[controller]"]
[APIController]
1 reference
public class AlbumController: ControllerBase
{
private readonly IAlbumsService _albumsService;
0 references
public AlbumController(IAlbumsService albumsService)
{
_albumsService = albumsService;
}
[HttpGet]
0 references
public IEnumerable GetAlbums()
}
return _albumsService.GetAlbums();
}
}
}

Вывод

Внедрение зависимостей позволяет клиенту удалить все знания о конкретной реализации. Это позволяет нам создавать более гибкий код и переключаться с одной реализации на другую, не меняя слой.
Мы можем легче тестировать наш код, не беспокоясь о побочных эффектах с внедрением зависимостей, поскольку это способствует повторному использованию, тестируемости и ремонтопригодность.

использованная литература

https://softwareengineering.stackexchange.com/questions/135971/когда-это-не-подходит-использовать-зависимость-инъекция-шаблон

https://www.blinkingcaret.com/2016/04/13/composition-superior-inheritance/

https://en.wikipedia.org/wiki/Dependency_injection

https://auth0.com/blog/dependency-injection-in-dotnet-core/

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1

https://www.tutorialsteacher.com/ioc