Les extensions de protocole ont été introduites dans Swift pour soutenir l'idéologie de la programmation orientée protocole : le programmeur peut intégrer des implémentations de méthodes par défaut directement au niveau du protocole, plutôt que par le biais d'une classe de base ou de fonctions globales. Cela réduit la duplication de code et permet d'adapter le comportement des types de manière flexible.
Le problème survient lorsque l'implémentation par défaut masque la nécessité d'une implémentation propre (override), ou lorsque la ligne de responsabilité devient floue — en particulier si le type implémente plusieurs protocoles avec des chevauchements. De plus, il est important de se rappeler : si une méthode est implémentée dans le type lui-même, elle écrasera toujours l'implémentation de l'extension.
La solution consiste à utiliser les extensions de protocole uniquement pour des comportements universels, et dans certains cas particuliers, à implémenter explicitement la méthode dans le type. Il est souhaitable d'éviter la surcharge des mêmes méthodes dans deux extensions pour un même protocole.
Exemple de code :
protocol Flyer { func fly() } extension Flyer { func fly() { print("Vol par défaut") } } struct Bird: Flyer {} let sparrow = Bird() sparrow.fly() // Affichera : Vol par défaut
Caractéristiques clés :
Une extension de protocole peut-elle ajouter une propriété stockée à un protocole ?
Non, seules les propriétés calculées et les méthodes peuvent être ajoutées dans les extensions de protocole. Les propriétés stockées sont interdites.
Que se passe-t-il si un protocole et un type ont des implémentations différentes de la méthode avec le même nom ? Laquelle sera appelée ?
Lorsqu'on appelle directement le type, l'implémentation du type sera appelée, mais lors de l'accès à une instance via une référence du type protocole, l'implémentation de l'extension du protocole sera appelée.
protocol Greeter { func greet() } extension Greeter { func greet() { print("Salut depuis l'extension") } } struct Person: Greeter { func greet() { print("Salut depuis le type") } } let person = Person() person.greet() // Salut depuis le type let greeter: Greeter = person greeter.greet() // Salut depuis l'extension
Peut-on utiliser des contraintes where dans une extension de protocole pour des limitations ?
Oui. C'est l'une des puissantes fonctionnalités — un protocole peut être étendu uniquement pour des types spécifiques.
extension Collection where Element: Equatable { func allEqual() -> Bool { guard let first = self.first else { return true } return allSatisfy { $0 == first } } }
** Cas négatif
L'équipe a décidé de mettre en œuvre la journalisation des erreurs via une extension de protocole, sans prévoir que chaque service pourrait vouloir ajouter son propre format spécifique. En fin de compte, différents services appellent la fonction via des références au protocole, et la logique de comportement diffère des attentes.
Avantages :
Inconvénients :
** Cas positif
Les protocoles ne sont étendus que pour les cas où le comportement est toujours universel. Pour des cas particuliers — l'implémentation explicite des méthodes dans le type, avec une revue de code sur les zones conflictuelles.
Avantages :
Inconvénients :