Управление жизненным циклом зависимостей — это организация создания, инициализации, обновления и уничтожения компонентов приложения таким образом, чтобы они были независимы друг от друга и легко тестировались. Для этого часто применяются IoC-контейнеры (Inversion of Control) и шаблон Dependency Injection (DI).
IoC-контейнер позволяет:
Пример на C# с использованием Microsoft.Extensions.DependencyInjection:
public interface IMessageSender { void Send(string msg); } public class EmailSender : IMessageSender { public void Send(string msg) { /* отправка email */ } } // Регистрация зависимостей var services = new ServiceCollection(); services.AddScoped<IMessageSender, EmailSender>(); // Получение экземпляра var provider = services.BuildServiceProvider(); var sender = provider.GetService<IMessageSender>(); sender.Send("Привет!");
Ключевые особенности:
Чем отличается внедрение зависимостей (DI) от шаблона Service Locator, и почему Service Locator считается антипаттерном?
Service Locator нарушает явную передачу зависимостей, делает код менее прозрачным. Лучше использовать DI через конструктор или методы, чтобы компилятор контролировал корректность зависимостей.
// Плохо: Service Locator var sender = ServiceLocator.Get<IMessageSender>(); // Хорошо: через DI public class MyService { public MyService(IMessageSender sender) { ... } }
В чём разница между Singleton паттерном и Single Instance временем жизни в DI-контейнере?
Паттерн Singleton реализуется вручную и не зависит от контейнера; Single Instance предоставляет экземпляр из контейнера, что безопаснее для unit-тестов и расширения.
Нужно ли внедрять зависимости во всех классах, даже простых утилитах?
Нет. Утилиты без зависимостей или слабосвязанные helper-классы (например, класс математических констант) внедрять DI смысла нет — это усложняет код, не принося пользы.