La composición de protocolos es un mecanismo en Swift que permite crear un tipo que debe conformarse a varios protocolos al mismo tiempo. Esta es una forma alternativa de reemplazar la herencia múltiple, que no está presente en Swift para las clases.
Historia del tema
Objective-C soportaba la herencia múltiple solo para protocolos, pero no para clases. Swift continúa esta tradición, enfocándose en los protocolos y su combinación para construir nuevas abstracciones.
Problema
A menudo, los programadores se enfrentan a la tarea de crear un tipo cuyo comportamiento está definido por varias abstracciones. La herencia múltiple a menudo conduce a conflictos en las jerarquías; en Swift, esto se resuelve de manera segura a través de protocolos y la composición de protocolos.
Solución
En Swift, se pueden combinar protocolos usando el operador '&'. Esto permite crear variables o parámetros de funciones que deben conformarse a varios protocolos al mismo tiempo.
Ejemplo de código:
protocol Drivable { func drive() } protocol Flyable { func fly() } struct FlyingCar: Drivable, Flyable { func drive() { print("Conduciendo") } func fly() { print("Volando") } } func testVehicle(_ vehicle: Drivable & Flyable) { vehicle.drive() vehicle.fly() } testVehicle(FlyingCar())
Características clave:
¿Se puede pasar un objeto que implemente solo uno de los protocolos a un parámetro con composición de protocolos?
No, el objeto debe implementar todos los protocolos involucrados en la composición, de lo contrario, el compilador generará un error.
Ejemplo de código:
// struct Car: Drivable {} — no se puede pasar a testVehicle, ya que fly() no está implementado
¿Funciona la composición de protocolos con tipos y no solo con valores?
La composición de protocolos se aplica a los valores (variables, parámetros de funciones), pero no se usa al definir el tipo de un objeto (por ejemplo, no se puede declarar un nuevo tipo como una "composición" de protocolos — solo una variable).
Ejemplo de código:
var obj: SomeProtocol & AnotherProtocol // permitido // typealias MyType = SomeClass & AnotherProtocol // error
¿Se pueden combinar clases y protocolos a través de &?
Sí, pero con una limitación: solo un tipo de clase (clase o su subclase) puede estar a la izquierda, los demás deben ser solo protocolos; de lo contrario, el compilador generará un error.
Ejemplo de código:
class A {} protocol B {} // func f(obj: A & B) {} // permitido // func f(obj: A & AnotherClass & B) {} // error! Solo un tipo de clase permitido
En el proyecto para la transferencia de datos entre capas, se utilizan objetos con composición de protocolos, aunque solo se necesitaba un protocolo:
func present(item: Displayable & Serializable) { ... }
Ventajas:
Uso de la composición de protocolos solo en casos explícitos: por ejemplo, el procesamiento de objetos que soportan tanto Codable como Identifiable para la serialización genérica:
func save<T: Codable & Identifiable>(_ item: T) { ... }
Ventajas: