Инъекция через конструктор
Передавайте зависимости через инициализаторы.
«Инъекция через конструктор» — бесплатный урок Swift Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Внедрение через конструктор
Самый распространённый способ DI — передавать зависимости через инициализатор. Объект получает всё необходимое при создании и сохраняет эти зависимости.
Простой init
Объявите хранимое свойство и присвойте ему значение в init. Вызывающий код должен предоставить зависимость, чтобы создать объект.
struct Greeter { func hi() -> String { "Hi" } }
struct View {
let greeter: Greeter
init(greeter: Greeter) { self.greeter = greeter }
func show() { print(greeter.hi()) }
}
View(greeter: Greeter()).show()Неизменяемые зависимости
Использование let для внедрённых свойств делает их неизменяемыми, поэтому зависимость нельзя заменить после создания объекта.
struct Engine { let hp: Int }
struct Car {
let engine: Engine // cannot change later
init(engine: Engine) { self.engine = engine }
}
let c = Car(engine: Engine(hp: 150))
print(c.engine.hp)Несколько зависимостей
Перечислите несколько параметров, чтобы внедрить более одной зависимости. Инициализатор документирует полный набор требований.
struct DB { func get() -> Int { 7 } }
struct Cache { func put(_ v: Int) { print("cached \(v)") } }
struct Service {
let db: DB
let cache: Cache
init(db: DB, cache: Cache) { self.db = db; self.cache = cache }
func run() { cache.put(db.get()) }
}
Service(db: DB(), cache: Cache()).run()Значения параметров по умолчанию
Значение по умолчанию позволяет не указывать зависимость в рабочем приложении, сохраняя возможность заменить её в тестах.
struct Logger { func log(_ m: String) { print(m) } }
struct Service {
let logger: Logger
init(logger: Logger = Logger()) { self.logger = logger }
func run() { logger.log("go") }
}
Service().run() // uses defaultВнедрение через конструктор класса
Классы следуют тому же принципу. Инициализатор присваивает каждую зависимость до того, как экземпляр становится доступным для использования.
class Mailer { func send() { print("sent") } }
class Signup {
let mailer: Mailer
init(mailer: Mailer) { self.mailer = mailer }
func go() { mailer.send() }
}
Signup(mailer: Mailer()).go()Внедрение значений
Зависимостями не обязательно должны быть объекты. Таким же образом можно внедрять значения конфигурации, например базовый URL или флаг.
struct Client {
let baseURL: String
init(baseURL: String) { self.baseURL = baseURL }
func endpoint(_ p: String) -> String { baseURL + p }
}
print(Client(baseURL: "https://api").endpoint("/users"))Корень композиции
В одном месте рядом с точкой входа приложения собирается весь граф объектов. Остальной код просто получает готовые зависимости.
struct DB { func count() -> Int { 3 } }
struct Repo { let db: DB; func n() -> Int { db.count() } }
struct App { let repo: Repo; func run() { print(repo.n()) } }
// Composition root:
let app = App(repo: Repo(db: DB()))
app.run()Избегание скрытых глобальных объектов
Внедрение через конструктор заменяет скрытый доступ к глобальным объектам. Каждая зависимость указана явно, поэтому можно проследить поток данных.
struct Settings { let theme: String }
struct Screen {
let settings: Settings
func render() { print("Theme: \(settings.theme)") }
}
Screen(settings: Settings(theme: "dark")).render()Обязательные и необязательные зависимости
Если зависимость действительно необязательна, представьте её необязательным типом; в противном случае сделайте её обязательной, чтобы объект никогда не существовал в частично настроенном состоянии.
struct Analytics { func track() { print("tracked") } }
struct Flow {
let analytics: Analytics?
func step() { analytics?.track() }
}
Flow(analytics: Analytics()).step()
Flow(analytics: nil).step()Почему внедрение через конструктор
Этот подход гарантирует полностью инициализированный объект, делает зависимости видимыми и совместим с неизменяемостью let. В Swift это рекомендуемый вариант по умолчанию.
struct Adder { func add(_ a: Int, _ b: Int) -> Int { a + b } }
struct Calc {
let adder: Adder
init(adder: Adder) { self.adder = adder }
}
print(Calc(adder: Adder()).adder.add(4, 5))Быстрая проверка
Почему внедрение через конструктор часто предпочитают другим вариантам?
Итоги
Внедрение через конструктор передаёт зависимости через init и сохраняет их, обычно в виде неизменяемых свойств let. Можно внедрять объекты или значения, задавать значения по умолчанию и собирать всё в корне композиции. Далее вы будете внедрять протоколы вместо конкретных типов.
Часто задаваемые вопросы
Урок «Инъекция через конструктор» бесплатный?
Да — полный текст урока «Инъекция через конструктор» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Инъекция через конструктор»?
Передавайте зависимости через инициализаторы. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Инъекция через конструктор»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Зачем нужна инъекция зависимостей
- Инъекция через конструктор
- Абстракции на основе протоколов
- Имитация зависимостей в тестах