Protocol-Oriented Programming
Protocol-Oriented Programming (POP, «протокол-ориентированное программирование») — парадигма разработки программного обеспечения, в которой поведение типов описывается через протоколы (интерфейсы), а не через иерархии наследования классов[1].
Что важно знать
| Protocol-Oriented Programming | |
|---|---|
| англ. Protocol-Oriented Programming | |
| Область использования | Программирование, Разработка программного обеспечения |
| Дата появления | 2015 |
| Место появления | конференция WWDC |
| Автор понятия | Дэйв Абрахамс |
Определение
Protocol-Oriented Programming концентрируется на следующих принципах:
- протоколы выступают «чертежами» поведения и определяют методы, свойства и прочие требования, не задавая их реализацию[2];
- композиция поведения осуществляется путём одновременного принятия множественных протоколов, что снижает необходимость глубокой иерархии наследования[3];
- расширения протоколов позволяют давать реализации по умолчанию, сокращая дублирование кода;
- парадигма отлично работает с типами-значениями (структурами и перечислениями), сохраняя преимущества неизменяемости и безопасности[4];
- широкое использование дженериков повышает гибкость и повторное использование алгоритмов.
Структурные элементы Protocol-Oriented Programming
- Протоколы — контракты, задающие требования к типам.
- Расширения протоколов — механизм добавления реализаций по умолчанию.
- Композиция протоколов — возможность комбинировать несколько протоколов для одного типа.
- Типы-значения (Struct, Enum) — получают требуемое поведение без наследования классов.
- Дженерики — обеспечивают обобщённость алгоритмов при работе с протоколами.
- Слабая связанность — модули взаимодействуют через абстрактные контракты, упрощая тестирование и поддержку[5].
Протоколы
Протокол в Swift объявляется ключевым словом protocol и может содержать:
- требования к методам (экземплярным и типовым), включая изменяемые (метка
mutating); - требования к свойствам (только чтение —
{ get }, или чтение/запись —{ get set }); - сабскрипты;
- ассоциированные типы (
associatedtype) для обобщённости; - множественное наследование других протоколов[6].
Расширения прототолов
Расширения (extension) позволяют:
- предоставлять реализацию по умолчанию для любых требований протокола;
- добавлять вычисляемые свойства и вспомогательные методы;
- использовать условные расширения с
where-клаузой для ограничений на типы[7]; - реализовать «ретроактивное» моделирование, расширяя протоколами уже существующие типы.
Полиморфизм и динамическая диспетчеризация
Полиморфизм достигается путём обращения к объектам через переменные протокольного типа: конкретная реализация метода выбирается во время выполнения посредством динамической диспетчеризации[8]. Swift использует:
- статическую диспетчеризацию для методов, определённых в расширениях протокола без явного требования в самом протоколе (быстрее);
- witness table — таблицы соответствий протоколу, чтобы во время выполнения найти нужную реализацию;
- виртуальные таблицы (v-table) для классов;
- message dispatch (самая динамичная, унаследована от Objective-C)[9].
Этапы применения
Применение протокол-ориентированного программирования обычно включает несколько последовательных этапов.
На этом этапе формулируются доменные поведения в виде небольших протоколов:
- выделяется контракт для каждой отдельной ответственности (SRP);
- предпочтение отдаётся композиции протоколов вместо наследования классов;
- используются расширения для общих реализаций;
- проектируется API так, чтобы зависимости вводились через абстракции, повышая тестируемость.
На этапе реализации:
- создаются типы (структуры, перечисления, классы), принимающие протоколы;
- добавляются реализации по умолчанию через расширения протоколов;
- активно применяются структуры и перечисления как типы-значения;
- осуществляется композиция протоколов (например,
typealias ReadableWritable = Readable & Writable); - используются ассоциированные типы и дженерики для повышения гибкости[10].
POP упрощает юнит-тестирование благодаря:
- лёгкому созданию моков и стабов, соответствующих тем же протоколам;
- низкой связанности кода и возможности изолировать тестируемый компонент;
- применению паттерна «Dependency Injection» через протокольные абстракции[11].
На этапе оптимизации анализируются накладные расходы, связанные с динамической диспетчеризацией и упаковкой экзистенциальных контейнеров. Для их снижения:
- методы и классы помечаются как
finalилиprivateдля включения статической диспетчеризации; - используются непрозрачные типы (
some Protocol) вместоany; - проводится профилирование и включается оптимизация компилятора (-O) для релизных сборок[12].
Поддерживаемость POP-кода обеспечивается:
- модульной структурой и чёткими контрактами;
- возможностью добавлять новое поведение через расширения, не трогая существующий код;
- простотой рефакторинга благодаря отсутствию глубокой иерархии наследования[13].
Преимущества и недостатки
- Повторное использование кода за счёт реализаций по умолчанию.
- Слабая связанность и высокая модульность архитектуры.
- Улучшенная тестируемость через легко заменяемые зависимости.
- Поддержка типов-значений и неизменяемости, повышающая надёжность.
- Отсутствие ограничений единичного наследования — тип может соответствовать множеству протоколов.
- Более высокая кривая обучения для новичков.
- Риск чрезмерного дробления кода на мелкие протоколы.
- Отсутствие хранимых свойств в протоколах заставляет искать обходные пути.
- Возможные накладные расходы динамической диспетчеризации при неосторожном использовании[14].
Сферы применения
- разработка приложений для iOS, iPadOS, watchOS и macOS;
- создание обобщённых алгоритмов и коллекций в стандартной библиотеке Swift;
- построение сетевых слоёв, где каждый эндпоинт моделируется как тип, соответствующий протоколу;
- декларативные UI-фреймворки (например, SwiftUI);
- расширение функциональности сторонних типов без изменения их исходного кода[15].
Инструменты для использования в Protocol-Oriented Programming
Языки программирования с поддержкой Protocol-Oriented Programming
Фреймворки Protocol-Oriented Programming
- SwiftUI — каждый визуальный компонент соответствует протоколу
View, а модификации описываются черезViewModifier. - Стандартная библиотека Swift — типы
Array,Dictionary,Stringреализуют протоколыCollection,Sequenceи другие, демонстрируя POP-подход.
Библиотеки Protocol-Oriented Programming
- Moya — сетевой слой, где каждый эндпоинт описывается протоколом
TargetTypeи расширениями[20]. - RxSwift — реактивный фреймворк, активно использующий протоколы
ObservableTypeиObserverTypeдля описания потоков событий.
Интеграция с другими парадигмами
POP органично сочетается с:
- объектно-ориентированным программированием — классы могут соответствовать протоколам и получать поведение через композицию;
- функциональным программированием — расширения протоколов предоставляют методы высшего порядка (
map,filter), а неизменяемые структуры поддерживают чистые функции[21].
Примечания
| Правообладателем данного материала является АНО «Интернет-энциклопедия «РУВИКИ». Использование данного материала на других сайтах возможно только с согласия АНО «Интернет-энциклопедия «РУВИКИ». |


