Ответ
Dependency Injection (DI) — это шаблон проектирования (паттерн) для реализации слабой связанности. Зависимости предоставляются объекту извне (внедряются), а не создаются им самим.
Способы внедрения:
- Через инициализатор (Constructor Injection) — наиболее предпочтительный.
- Через свойство (Property Injection).
- Через метод (Method Injection).
Dependency Inversion Principle (DIP) — это принцип проектирования, пятый принцип SOLID. Он декларирует:
- Модули верхнего уровня (политика) не должны зависеть от модулей нижнего уровня (детали). Оба должны зависеть от абстракций (интерфейсов/протоколов).
- Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Взаимосвязь: DI является распространенным механизмом для соблюдения DIP. DIP задает цель (зависимость от абстракций), а DI предоставляет способ её достижения (внедрение этих абстракций).
Пример без DIP/DI (плохо):
class Service { func fetch() { /* ... */ } }
class ViewModel {
private let service = Service() // Прямая зависимость от конкретного класса
func load() { service.fetch() }
}
Пример с DIP и DI (хорошо):
// Абстракция (DIP)
protocol DataFetcherProtocol {
func fetch()
}
// Деталь (DIP)
class NetworkService: DataFetcherProtocol {
func fetch() { /* сетевой запрос */ }
}
class MockService: DataFetcherProtocol {
func fetch() { /* тестовые данные */ }
}
// Модуль верхнего уровня (DIP + DI)
class ViewModel {
private let fetcher: DataFetcherProtocol
// Внедрение зависимости (DI) через инициализатор
init(fetcher: DataFetcherProtocol) {
self.fetcher = fetcher // Зависит от абстракции
}
func load() { fetcher.fetch() }
}
// Использование
let realVM = ViewModel(fetcher: NetworkService()) // Продакшен
let testVM = ViewModel(fetcher: MockService()) // Тесты