En Kotlin, la délégation de comportement est implémentée par le mécanisme langage du mot clé by, directement dans la signature de la classe. Cela permet de transmettre automatiquement les appels de méthodes d'une interface (ou de plusieurs interfaces) à un autre objet avec une implémentation, réduisant le boilerplate et facilitant la composition.
L'apparition de la délégation d'interface est une tentative d'éliminer les limitations et les inconvénients de l'héritage multiple. C'est l'idée de "composition plutôt qu'héritage" – nous déléguons le comportement sans avoir recours à une hiérarchie de classes. Inspiré de langages où la composition est plus populaire (par exemple, Go, Scala).
En Java et dans d'autres langages, il est souvent nécessaire de créer une interface et de mettre en œuvre manuellement chaque méthode, en transmettant la logique à un autre champ (patron Adaptateur d'Objet), ce qui devient rapidement obsolète avec l'augmentation du nombre de méthodes.
Kotlin permet de déléguer une interface de manière déclarative avec by :
interface Logger { fun log(msg: String) } class ConsoleLogger: Logger { override fun log(msg: String) = println(msg) } class Service(logger: Logger): Logger by logger { fun doWork() { log("Travail commencé") // ... } } val service = Service(ConsoleLogger()) service.doWork()
Caractéristiques clés :
Que se passe-t-il si nous ajoutons notre propre méthode d'interface avec la même signature dans la classe Service ?
La mise en œuvre propre "écrase" la délégation — donc la méthode définie explicitement dans la classe prévaut :
class Service(logger: Logger): Logger by logger { override fun log(msg: String) = println("PRÉFIXE: $msg") }
Un même classe peut-elle déléguer plusieurs interfaces à différents objets ?
Oui, une classe peut implémenter et déléguer plusieurs interfaces à différents objets, mais chaque interface est déléguée à un seul objet :
class Service( logger: Logger, tracker: Tracker ): Logger by logger, Tracker by tracker
En quoi la délégation d'interface diffère-t-elle de la délégation de propriétés via by ?
La classe implémente manuellement l'interface, chaque méthode appelle le délégué, et en ajoutant de nouvelles méthodes, on oublie de mettre à jour le proxy, ce qui entraîne des erreurs.
Avantages :
Inconvénients :
La délégation linguistique est utilisée, seules les méthodes non standard sont implémentées à l'intérieur de la classe, la nouvelle fonctionnalité est ajoutée sans changements majeurs.
Avantages :
Inconvénients :