Зачем нужна инъекция зависимостей
Отделяйте создание объектов от их использования для удобства тестирования.
«Зачем нужна инъекция зависимостей» — бесплатный урок Swift Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Зачем нужно внедрение зависимостей
Внедрение зависимостей (DI) означает передачу объекту необходимых ему компонентов извне вместо их самостоятельного создания. Это уменьшает связанность компонентов и упрощает их тестирование.
Проблема: жёсткая связанность
Если тип сам создаёт используемые им компоненты, он оказывается привязан к конкретным классам, и его нельзя перенастроить или протестировать изолированно.
class Logger {
func log(_ m: String) { print("LOG: \(m)") }
}
class Service {
let logger = Logger() // hard-coded dependency
func run() { logger.log("running") }
}
Service().run()Связанность мешает тестированию
Поскольку Service всегда создаёт настоящий Logger, тест не может перехватить или имитировать вывод журнала. Зависимость остаётся невидимой извне.
class Logger { func log(_ m: String) { print(m) } }
class Service {
let logger = Logger()
func run() { logger.log("hello") }
}
// No way to swap Logger here.
Service().run()Идея: внедрите зависимость
Вместо этого передайте зависимость извне. Вызывающий код решает, какую реализацию предоставить, поэтому Service больше не заботится об этом.
class Logger { func log(_ m: String) { print("LOG: \(m)") } }
class Service {
let logger: Logger
init(logger: Logger) { self.logger = logger }
func run() { logger.log("running") }
}
Service(logger: Logger()).run()Преимущества уменьшения связанности
При внедрении один и тот же Service работает с разными регистраторами как в рабочем приложении, так и в тестах, без изменения собственного кода.
class Logger { var lines: [String] = []
func log(_ m: String) { lines.append(m) } }
class Service {
let logger: Logger
init(logger: Logger) { self.logger = logger }
func run() { logger.log("event") }
}
let l = Logger()
Service(logger: l).run()
print(l.lines)Единственная ответственность
DI поддерживает принцип единственной ответственности: тип сосредоточен на своей задаче и передаёт остальные обязанности внедрённым компонентам.
struct Mailer { func send(_ to: String) { print("Mail to \(to)") } }
struct SignupFlow {
let mailer: Mailer
func register(_ email: String) { mailer.send(email) }
}
SignupFlow(mailer: Mailer()).register("a@b.com")Гибкость
Вы можете по-новому комбинировать объекты. Связывание выполняется на границах приложения, поэтому его ядро остаётся гибким.
struct Engine { let power: Int }
struct Car {
let engine: Engine
func describe() { print("Power: \(engine.power)") }
}
Car(engine: Engine(power: 200)).describe()
Car(engine: Engine(power: 90)).describe()Явные зависимости
Инициализатор, перечисляющий зависимости, точно документирует потребности типа. Скрытые зависимости, создаваемые внутри, скрывают этот контракт.
struct Repo { func load() -> [Int] { [1, 2, 3] } }
struct Report {
let repo: Repo // visible dependency
func total() -> Int { repo.load().reduce(0, +) }
}
print(Report(repo: Repo()).total())Композиция вместо создания
DI поощряет сборку объектов извне. Небольшая точка сборки формирует граф, а остальной код просто получает всё необходимое.
struct DB { func count() -> Int { 42 } }
struct Stats { let db: DB; func show() { print(db.count()) } }
// Composition root:
let app = Stats(db: DB())
app.show()Не только для больших приложений
Преимущества есть даже у небольших программ: внедрение зависимости позволяет заменять поведение и делает намерения ясными без дополнительных фреймворков.
struct Clock { func now() -> Int { 12 } }
struct Greeter {
let clock: Clock
func greet() { print(clock.now() < 12 ? "Morning" : "Afternoon") }
}
Greeter(clock: Clock()).greet()Фреймворк не требуется
Для DI в Swift не нужна библиотека. Достаточно обычных инициализаторов и протоколов. В следующих уроках рассматриваются внедрение через конструктор, протоколы и создание имитаций.
struct Adder { func add(_ a: Int, _ b: Int) -> Int { a + b } }
struct Calc {
let adder: Adder
func run() { print(adder.add(2, 3)) }
}
Calc(adder: Adder()).run()Быстрая проверка
В чём заключается основная идея внедрения зависимостей?
Итоги
Внедрение зависимостей передаёт используемые компоненты извне, а не создаёт их внутри, благодаря чему уменьшается связанность, зависимости становятся понятнее и появляется возможность тестирования. В Swift для этого не нужен фреймворк. Далее вы рассмотрите самый распространённый вариант: внедрение через конструктор.
Часто задаваемые вопросы
Урок «Зачем нужна инъекция зависимостей» бесплатный?
Да — полный текст урока «Зачем нужна инъекция зависимостей» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Зачем нужна инъекция зависимостей»?
Отделяйте создание объектов от их использования для удобства тестирования. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Зачем нужна инъекция зависимостей»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Зачем нужна инъекция зависимостей
- Инъекция через конструктор
- Абстракции на основе протоколов
- Имитация зависимостей в тестах