Что такое состав протокола?
Это процесс объединения нескольких протоколов в один протокол. Вы можете думать об этом как о множественном наследовании, за исключением протоколов.
Давайте посмотрим на некоторые примеры.
Приведенная ниже реализация представляет собой собаку, которая может лаять и вилять хвостом при вызове ballFound().
protocol CanDoDogThings { func bark() func waggTail() } struct Runner { let dog: CanDoDogThings func ballFound() { dog.waggTail() dog.bark() } }
Это простая и удобная реализация, так как она четко определяет, что собака способна делать, когда мяч найден, вилять хвостом и лаять. Этот подход также можно легко протестировать, поскольку экземпляры можно имитировать. Однако по мере роста вашего приложения вы можете ввести больше зависимостей, таких как прыжки или еда. Таким образом, вы можете в конечном итоге написать одинаковый шаблонный код для каждого, что может привести к проблемам с обслуживанием, а никто из нас этого не хочет!
Что нам нужно, так это простота обслуживания, но при этом получение всех преимуществ прямого и прямого внедрения зависимостей.
Примем состав протокола.
protocol CanBark { func bark() } protocol CanWaggTail { func waggTail() } struct Dog { // Protocol Composition typealias Dependency = CanBark & CanWaggTail let dogManager: Dependency func ballFound() { dogManager.waggTail() dogManager.bark() } } /*----- Another Way! -----*/ // Protocol Composition protocol CanDoDogThings: CanBark, CanWaggTail { } struct Dog { let dogManager: CanDoDogThings func ballFound() { dogManager.waggTail() dogManager.bark() } }
Таким образом, композиция может быть выполнена по-разному.
Мне нравятся оба подхода, так как все зависимости теперь объединены, а не несколько непересекающихся протоколов:
- Все зависимости теперь четко определены.
- Единая точка входа верхнего уровня, чтобы управлять ими всеми 😅.
- Компилятор может обеспечить реализацию полного протокола.
- В целом он кажется более чистым и сплоченным.
Исследуйте реальный пример на здесь.