La composition de protocoles est un mécanisme en Swift qui permet de créer un type qui doit se conformer à plusieurs protocoles en même temps. C'est un moyen alternatif de remplacer l'héritage multiple, qui n'existe pas pour les classes en Swift.
Historique de la question
Objective-C supportait l'héritage multiple uniquement pour les protocoles, mais pas pour les classes. Swift développe cette tradition en mettant l'accent sur les protocoles et leur combinaison pour construire de nouvelles abstractions.
Problème
Les programmeurs sont souvent confrontés à la tâche de créer un type dont le comportement est défini par plusieurs abstractions. L'héritage multiple entraîne inévitablement des conflits d'hierarchies, et en Swift, cela est résolu de manière sécurisée grâce aux protocoles et à la composition de protocoles.
Solution
En Swift, il est possible de combiner des protocoles à l'aide de l'opérateur '&'. Cela permet de créer des variables ou des paramètres de fonction qui doivent se conformer à plusieurs protocoles simultanément.
Exemple de code :
protocol Drivable { func drive() } protocol Flyable { func fly() } struct FlyingCar: Drivable, Flyable { func drive() { print("Driving") } func fly() { print("Flying") } } func testVehicle(_ vehicle: Drivable & Flyable) { vehicle.drive() vehicle.fly() } testVehicle(FlyingCar())
Caractéristiques clés :
Peut-on passer un objet qui implémente seulement un des protocoles en paramètre d'une composition de protocoles ?
Non, l'objet doit implémenter tous les protocoles impliqués dans la composition, sinon le compileur renverra une erreur.
Exemple de code :
// struct Car: Drivable {} — ne peut pas être passé à testVehicle car fly() n'est pas implémenté
La composition de protocoles fonctionne-t-elle avec des types, et pas seulement avec des valeurs ?
La composition de protocoles s'applique aux valeurs (variables, paramètres de fonctions), mais n'est pas utilisée lors de la définition du type d'un objet (par exemple, on ne peut pas déclarer un nouveau type comme une "composition" de protocoles — seulement une variable).
Exemple de code :
var obj: SomeProtocol & AnotherProtocol // permis // typealias MyType = SomeClass & AnotherProtocol // erreur
Peut-on combiner des classes et des protocoles via '&' ?
Oui, mais avec une seule restriction : un seul type de classe (classe ou son successeur) peut être à gauche, les autres ne peuvent être que des protocoles, sinon le compileur renverra une erreur.
Exemple de code :
class A {} protocol B {} // func f(obj: A & B) {} // permis // func f(obj: A & AnotherClass & B) {} // erreur ! Un seul type de classe est autorisé
Dans un projet, pour le transfert de données entre couches, des objets avec une composition de protocoles sont utilisés, alors qu'un seul protocole aurait suffi :
func present(item: Displayable & Serializable) { ... }
Avantages :
Utilisation de la composition de protocoles uniquement dans des cas explicites — par exemple, traitement d'objets qui supportent à la fois Codable et Identifiable pour la sérialisation générique :
func save<T: Codable & Identifiable>(_ item: T) { ... }
Avantages :