Вопрос проверяет понимание принципа внедрения зависимостей и его реализации для повышения тестируемости и гибкости кода.
Внедрение зависимостей — это паттерн проектирования, при котором объект получает свои зависимости извне, а не создаёт их самостоятельно. Это реализует принцип инверсии управления, делая код менее связанным и более тестируемым.
Класс объявляет свои зависимости через интерфейсы или абстрактные типы в конструкторе, свойствах или методах. Внешний код (например, фабрика, контейнер IoC или точка входа приложения) отвечает за создание и передачу конкретных реализаций этих зависимостей.
// Интерфейс зависимости
public interface ILogger {
void Log(string message);
}
// Реальная реализация
public class FileLogger : ILogger {
public void Log(string message) {
// Запись в файл
}
}
// Класс, использующий зависимость
public class OrderProcessor {
private readonly ILogger _logger;
// Зависимость внедряется через конструктор
public OrderProcessor(ILogger logger) {
_logger = logger;
}
public void Process(Order order) {
// Логика обработки
_logger.Log("Order processed");
}
}
// В продакшене
var realLogger = new FileLogger();
var processor = new OrderProcessor(realLogger);
// В тесте можно подменить зависимость на mock
var mockLogger = new MockLogger(); // Заглушка
var testProcessor = new OrderProcessor(mockLogger);
// Теперь можно проверить, был ли вызван LogЭтот подход широко используется в современных фреймворках (Spring, .NET Core, Nest.js) для управления жизненным циклом объектов и конфигурации приложения. Он особенно полезен для модульного тестирования, так как позволяет изолировать тестируемый модуль от внешних систем (баз данных, API, файловой системы).
Вывод: Внедрение зависимостей следует применять, когда требуется повысить тестируемость кода, уменьшить связность между компонентами и сделать архитектуру более гибкой для будущих изменений.