0Pricing
Swift Academy · Урок

Зачем нужна инъекция зависимостей

Отделяйте создание объектов от их использования для удобства тестирования.

«Зачем нужна инъекция зависимостей» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Зачем нужна инъекция зависимостей
  2. Инъекция через конструктор
  3. Абстракции на основе протоколов
  4. Имитация зависимостей в тестах
← Назад к Swift Academy