ProgrammationDéveloppeur Android/Kotlin

Qu'est-ce que les interfaces sealed en Kotlin, comment et pourquoi les utiliser ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Interface sealed — c'est un type spécial d'interface en Kotlin qui permet de restreindre le nombre de ses implémentations à l'intérieur d'un module. Les classes sealed sont apparues en premier dans Kotlin, tandis que les interfaces sealed ont été ajoutées à partir de Kotlin 1.5 comme une évolution pour un meilleur contrôle sur les types impliqués, par exemple, dans les hiérarchies d'états ou le traitement d'événements.

Historique de la question

Auparavant, les développeurs utilisaient des classes sealed pour limiter l'héritage et créer des hiérarchies sûres. Cependant, pour plus de flexibilité et de soutien aux structures où l'héritage de plusieurs types est utile, des interfaces sealed étaient nécessaires.

Problème

Sans interfaces sealed, il est impossible de gérer de manière flexible l'ensemble des sous-classes de l'interface. Cela rend impossible, par exemple, une vérification exhaustive dans un when lors du traitement des états, si tout est construit sur des interfaces plutôt que sur des classes abstraites/concrètes.

Solution

L'utilisation de l'interface sealed permet de :

  • Décrire un ensemble fixe d'implémentations.
  • Garantir que toutes les implémentations sont connues du compilateur.
  • Utiliser en toute sécurité when sans la branche else — le compilateur signalera les cas non couverts.

Exemple de code :

sealed interface Event class Click : Event class Scroll : Event fun handle(event: Event) = when(event) { is Click -> println("Événement de clic") is Scroll -> println("Événement de défilement") }

Caractéristiques clés :

  • Rétrécissement et contrôle de l'ensemble des réalisations autorisées.
  • Possibilité d'hériter simultanément de plusieurs interfaces sealed.
  • Sécurité lors du pattern matching (when).

Questions pièges.

Les interfaces sealed peuvent-elles avoir des implémentations en dehors de leur fichier de déclaration ?

Non, les implémentations de l'interface sealed doivent se trouver dans le même module. Cela garantit une exhaustivité totale et permet au compilateur de contrôler leur nombre.

Comment les interfaces sealed interagissent-elles avec les classes et les objets ?

Une interface sealed peut être implémentée à la fois par des classes ordinaires et des classes object, ainsi que par des objets de données (Kotlin 1.9+). Une telle interface peut apparaître dans un héritage multiple, ce qui n'est pas possible avec une classe sealed.

sealed interface Operation object Add: Operation object Subtract: Operation

Les interfaces sealed peuvent-elles être imbriquées ?

Oui, on peut déclarer une interface sealed à l'intérieur d'une autre classe sealed ou au-dessus d'autres interfaces. L'essentiel est que toutes les implémentations soient dans un même module.

Erreurs typiques et anti-patterns

  • Définir des réalisations d'interface sealed dans différents modules entraîne des erreurs de compilation.
  • Tenter d'utiliser une interface sealed en partant du principe qu'elle fonctionne comme une classe sealed, bien que l'interface sealed puisse être héritée par d'autres interfaces.

Exemple de la vie réelle

Cas négatif

Dans l'application, les états de l'UI ont été décrits simplement comme des interfaces sans le modificateur sealed. Une implémentation a été oubliée, l'analyse statique ne l'a pas détectée ; l'erreur n'est apparue qu'en production.

Avantages :

  • Modèle d'interfaces Java familier.

Inconvénients :

  • Pas de garanties d'exhaustivité dans when.
  • Vulnérabilité à l'apparition d'implémentations "externes".

Cas positif

Utilisation de l'interface sealed pour le modèle d'événements d'écran. Toutes les implémentations se trouvent dans un même fichier de module, le compilateur avertit lors des branches non fermées lorsque des cas sont omis dans when.

Avantages :

  • Sécurité de type complète.
  • Commodité de support et d'extension.

Inconvénients :

  • Utilisation uniquement dans le cadre d'un même module.