Browse Source

Добавить 'Лекции/CSharp/DependencyInjection.md'

u21-25tolstikov 6 months ago
parent
commit
d65356e9ea
1 changed files with 135 additions and 0 deletions
  1. 135 0
      Лекции/CSharp/DependencyInjection.md

+ 135 - 0
Лекции/CSharp/DependencyInjection.md

@@ -0,0 +1,135 @@
+# Лекция: Dependency Injection и внедрение зависимостей в C#: принципы, паттерны и применение
+## Введение
+Dependency Injection (DI, внедрение зависимостей) — это один из ключевых принципов проектирования программного обеспечения, который помогает создавать гибкие, тестируемые и поддерживаемые приложения. Внедрение зависимостей позволяет разделять компоненты системы, уменьшая связанность между ними. В C# DI активно используется в современных фреймворках, таких как ASP.NET Core. В этой лекции мы разберем основные принципы DI, его паттерны и практическое применение.
+
+## Основные принципы Dependency Injection
+Внедрение зависимостей основано на принципе инверсии зависимостей (Dependency Inversion Principle, DIP), который гласит, что модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба типа модулей должны зависеть от абстракций. Абстракции не должны зависеть от деталей, а детали должны зависеть от абстракций.
+
+DI позволяет передавать зависимости (сервисы) в классы извне, вместо того чтобы классы создавали их самостоятельно. Это делает код более модульным и упрощает тестирование.
+
+Пример без DI:
+
+```
+public class UserService
+{
+    private readonly EmailService _emailService;
+
+    public UserService()
+    {
+        _emailService = new EmailService(); // Зависимость создается внутри класса
+    }
+
+    public void RegisterUser(string email)
+    {
+        _emailService.SendEmail(email, "Welcome!");
+    }
+}
+```
+
+Пример с DI:
+```
+public class UserService
+{
+    private readonly IEmailService _emailService;
+
+    public UserService(IEmailService emailService) // Зависимость внедряется извне
+    {
+        _emailService = emailService;
+    }
+
+    public void RegisterUser(string email)
+    {
+        _emailService.SendEmail(email, "Welcome!");
+    }
+}
+```
+## Паттерны внедрения зависимостей
+Существует три основных способа внедрения зависимостей:
+
+Внедрение через конструктор (Constructor Injection): Зависимости передаются через конструктор класса. Это наиболее предпочтительный способ, так как он делает зависимости явными и обязательными.
+
+Внедрение через свойства (Property Injection): Зависимости устанавливаются через публичные свойства. Этот способ менее строгий и используется реже.
+
+Внедрение через методы (Method Injection): Зависимости передаются в качестве параметров метода. Этот способ полезен, когда зависимость требуется только для одного метода.
+
+Пример внедрения через конструктор:
+
+```
+public class UserService
+{
+    private readonly IEmailService _emailService;
+
+    public UserService(IEmailService emailService)
+    {
+        _emailService = emailService;
+    }
+}
+```
+## Контейнеры зависимостей
+Контейнер зависимостей — это инструмент, который управляет созданием и жизненным циклом объектов, а также автоматически разрешает зависимости. В ASP.NET Core встроен контейнер зависимостей, который позволяет регистрировать сервисы и внедрять их в классы.
+
+Пример регистрации сервиса в контейнере:
+```
+public void ConfigureServices(IServiceCollection services)
+{
+    services.AddTransient<IEmailService, EmailService>(); // Регистрация сервиса
+}
+```
+Пример использования зарегистрированного сервиса:
+
+```
+public class UserController : Controller
+{
+    private readonly IEmailService _emailService;
+
+    public UserController(IEmailService emailService)
+    {
+        _emailService = emailService;
+    }
+}
+```
+## Жизненные циклы сервисов
+В ASP.NET Core существует три основных жизненных цикла сервисов:
+
+- Transient: Сервис создается каждый раз, когда он запрашивается. Подходит для легковесных сервисов без состояния.
+
+- Scoped: Сервис создается один раз в пределах области (например, HTTP-запроса). Это наиболее часто используемый жизненный цикл.
+
+- Singleton: Сервис создается один раз и используется на протяжении всего времени жизни приложения. Подходит для сервисов, которые должны быть общими для всех пользователей.
+
+Пример регистрации сервиса с разными жизненными циклами:
+
+```
+services.AddTransient<IEmailService, EmailService>(); // Transient
+services.AddScoped<IUserRepository, UserRepository>(); // Scoped
+services.AddSingleton<ILogger, Logger>(); // Singleton
+```
+## Преимущества и лучшие практики DI
+Использование DI имеет множество преимуществ:
+
+- Уменьшение связанности: Классы зависят от абстракций, а не от конкретных реализаций.
+
+- Упрощение тестирования: Зависимости можно легко подменять mock-объектами в unit-тестах.
+
+- Гибкость: Изменение реализации сервиса не требует изменения классов, которые его используют.
+
+Лучшие практики использования DI включают:
+
+- Использование интерфейсов для абстракций.
+
+- Предпочтение внедрения через конструктор.
+
+- Избегание сервис-локатора (Service Locator), так как это скрывает зависимости и усложняет код.
+
+- Регистрация всех зависимостей в контейнере на старте приложения.
+
+## Вопросы для самопроверки:
+1. В чем заключается принцип инверсии зависимостей (DIP)?
+
+2. Какие существуют способы внедрения зависимостей и какой из них наиболее предпочтителен?
+
+3. Какой жизненный цикл сервиса используется по умолчанию в ASP.NET Core?
+
+4. Какие преимущества дает использование Dependency Injection?
+
+5. Почему следует избегать использования сервис-локатора (Service Locator)?