ProgramaciónSwift Middle/Lead

¿Qué es la composición de protocolos en Swift, cómo funciona en la práctica y cuándo debe aplicarse en lugar de la herencia múltiple o el uso normal de protocolos?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

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:

  • El operador '&' permite combinar varios protocolos para una variable o un parámetro de función.
  • Funciona tanto para clases como para estructuras y enumeraciones.
  • Permite describir explícitamente el comportamiento necesario sin crear tipos intermedios.

Preguntas engañosas.

¿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

Errores comunes y anti-patrones

  • Esperar que funcione como la herencia múltiple de clases.
  • Usar la composición innecesariamente cuando un solo protocolo es suficiente.
  • Romper contratos al usar bibliotecas externas y composición de protocolos.

Ejemplo de la vida real

Caso negativo

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:

  • Interfaz flexible y ampliable. Desventajas:
  • Complejidad y confusión si la mayoría de los objetos transferidos no requieren todas las funcionalidades.

Caso positivo

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:

  • Descripción clara del requisito para el tipo.
  • Minimización de errores. Desventajas:
  • Puede complicar ligeramente la firma de las funciones.