0Pricing
Swift Academy · Урок

Абстракции на основе протоколов

Зависите от протоколов, а не от конкретных типов.

«Абстракции на основе протоколов» — бесплатный урок Swift Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Абстракции на основе протоколов

Внедрение протокола вместо конкретного типа позволяет свободно заменять реализации. Потребитель зависит только от поведения, а не от класса.

Определение протокола

Опишите возможность с помощью протокола. В качестве зависимости можно передать любой соответствующий ему тип.

protocol Logging {
    func log(_ message: String)
}
print("Protocol describes behavior, not a concrete class.")

Соответствие конкретного типа

Настоящая реализация соответствует протоколу. Именно она используется как зависимость в рабочем приложении.

protocol Logging { func log(_ m: String) }
struct ConsoleLogger: Logging {
    func log(_ m: String) { print("LOG: \(m)") }
}
ConsoleLogger().log("ready")

Зависимость от протокола

Тип свойства потребителя — это протокол, поэтому оно принимает любое соответствующее ему значение.

protocol Logging { func log(_ m: String) }
struct ConsoleLogger: Logging { func log(_ m: String) { print(m) } }
struct Service {
    let logger: Logging // protocol, not ConsoleLogger
    func run() { logger.log("running") }
}
Service(logger: ConsoleLogger()).run()

Замена реализаций

Поскольку типом является протокол, можно передать другую соответствующую ему реализацию, не изменяя потребитель.

protocol Logging { func log(_ m: String) }
struct Loud: Logging { func log(_ m: String) { print(m.uppercased()) } }
struct Quiet: Logging { func log(_ m: String) {} }
struct Service { let logger: Logging; func run() { logger.log("hi") } }
Service(logger: Loud()).run()
Service(logger: Quiet()).run()

Программирование на основе интерфейсов

Это принцип «зависите от абстракций, а не от конкретных реализаций». Код высокого уровня защищён от низкоуровневых деталей.

protocol Storage { func save(_ v: Int) }
struct MemoryStore: Storage { func save(_ v: Int) { print("kept \(v)") } }
struct Manager { let store: Storage; func add() { store.save(1) } }
Manager(store: MemoryStore()).add()

Несколько соответствующих типов

Один и тот же протокол могут реализовывать несколько типов, каждый из которых подходит для своего контекста: сети, диска или памяти.

protocol Source { func value() -> Int }
struct Fixed: Source { func value() -> Int { 10 } }
struct Doubler: Source { func value() -> Int { 20 } }
func use(_ s: Source) { print(s.value()) }
use(Fixed())
use(Doubler())

Протоколы со связанным поведением

Протоколы могут объявлять несколько методов, формируя ясный контракт для зависимости.

protocol Cache {
    func get(_ key: String) -> Int?
    func set(_ key: String, _ v: Int)
}
struct Dict: Cache {
    var store: [String: Int] = [:]
    func get(_ k: String) -> Int? { store[k] }
    mutating func set(_ k: String, _ v: Int) { store[k] = v }
}
var c = Dict(); c.set("a", 1)
print(c.get("a") ?? -1)

Ограничения обобщений

Зависимость также можно внедрить через обобщённый параметр с ограничением на протокол, избежав накладных расходов на работу с экзистенциальным типом.

protocol Greeter { func greet() -> String }
struct English: Greeter { func greet() -> String { "Hello" } }
struct Welcome<G: Greeter> {
    let greeter: G
    func show() { print(greeter.greet()) }
}
Welcome(greeter: English()).show()

Стабильные контракты

Пока протокол остаётся стабильным, реализации могут меняться внутри, не нарушая работу потребителей.

protocol Formatter { func format(_ n: Int) -> String }
struct Plain: Formatter { func format(_ n: Int) -> String { "\(n)" } }
struct Padded: Formatter { func format(_ n: Int) -> String { String(format: "%03d", n) } }
func render(_ f: Formatter) { print(f.format(7)) }
render(Plain())
render(Padded())

Подготовка к созданию имитаций

Особенно важно, что протоколы позволяют тестам подставлять имитацию вместо настоящей реализации. Именно этому посвящён следующий урок.

protocol Network { func fetch() -> String }
struct Real: Network { func fetch() -> String { "server data" } }
struct VM { let net: Network; func load() { print(net.fetch()) } }
VM(net: Real()).load()

Быстрая проверка

Зачем внедрять тип протокола вместо конкретного класса?

Итоги

Внедрение протокола скрывает конкретный тип, поэтому вместо него можно подставить любую соответствующую реализацию. Это соответствует принципу «зависите от абстракций» и позволяет использовать альтернативные реализации и, что особенно важно, тестовые двойники. Далее: имитация зависимостей в тестах.

Часто задаваемые вопросы

Урок «Абстракции на основе протоколов» бесплатный?

Да — полный текст урока «Абстракции на основе протоколов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Абстракции на основе протоколов»?

Зависите от протоколов, а не от конкретных типов. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Абстракции на основе протоколов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

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

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