
Les classes scellées (ou “sealed class” en anglais) sont un concept de programmation disponible dans le langage de programmation Kotlin. Elles permettent de définir des classes qui ne peuvent être étendues (ou sous-classées) que dans le même fichier de source.
Cela peut être utile pour créer des types de données qui ne peuvent prendre qu’un nombre fini de valeurs possibles.
Voici un exemple de définition d’une classe scellée en Kotlin :
sealed class Shape
{
class Circle(val radius: Double) : Shape()
class Rectangle(val width: Double, val height: Double) : Shape()
class Triangle(val base: Double, val height: Double) : Shape()
}
Dans cet exemple, la classe Shape
est définie comme étant sealed. Elle ne peut être étendue que par les classes Circle
, Rectangle
et Triangle
, qui sont définies dans le même fichier de source.
Il est important de noter que les classes filles d’une classe scellée doivent être définies comme des classes internes à la classe scellée, comme dans l’exemple ci-dessus.
Sinon, vous obtiendrez une erreur de compilation.
Pour utiliser une “sealed class”, vous pouvez utiliser un bloc when
pour vérifier les différentes instances possibles :
fun calculateArea(shape: Shape): Double
{
return when (shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.height
is Shape.Triangle -> shape.base * shape.height / 2
}
}
Dans cet exemple, le bloc when
vérifie si l’instance de shape
est une instance de Shape.Circle
, Shape.Rectangle
ou Shape.Triangle
, et renvoie la surface appropriée en conséquence.
Il est important de noter que, contrairement aux classes ordinaires, il n’est pas nécessaire de fournir un cas “par défaut” dans un bloc when
qui utilise une classe scellée, car le compilateur peut garantir qu’il existe une correspondance pour toutes les valeurs possibles.
En résumé, les sealed class en Kotlin permettent de définir des classes qui ne peuvent être étendues (ou sous-classées) que dans le même fichier de source, et sont utiles pour créer des types de données qui ne peuvent prendre qu’un nombre fini de valeurs possibles.
Pour utiliser une classe scellée, vous pouvez utiliser un bloc when
pour vérifier les différentes instances possibles.
Il est important de noter que les classes filles d’une classe scellée doivent être définies comme des classes internes à la classe scellée, et qu’il n’est pas nécessaire de fournir un cas “par défaut”, car le compilateur peut garantir qu’il existe une correspondance pour toutes les valeurs possibles.
Voici un exemple d’utilisation d’une classe scellée pour représenter les états d’une application :
sealed class AppState
{
object Loading : AppState()
object Authenticated : AppState()
object Unauthenticated : AppState()
data class Error(val message: String) : AppState()
}
Dans cet exemple, la classe AppState
représente les différents états que l’application peut prendre: Loading
, Authenticated
, Unauthenticated
et Error
.
Chacun de ces états est une classe interne à AppState
qui étend la classe scellée.
On peut maintenant utiliser un bloc when
pour gérer les différents états de l’application de la manière suivante :
fun handleAppState(state: AppState)
{
when(state)
{
is AppState.Loading -> showLoading()
is AppState.Authenticated -> showAuthenticated()
is AppState.Unauthenticated -> showUnauthenticated()
is AppState.Error -> showError(state.message)
}
}
En utilisant des sealed class, vous pouvez vous assurer que tous les états possibles de votre application sont explicitement définis et gérés, ce qui peut aider à éviter les bugs liés à des états non gérés ou non prévus.
Il y a encore d’autres aspects importants à couvrir lorsqu’il s’agit de classes scellées en Kotlin.
- Il est possible de définir des propriétés et des méthodes sur les classes scellées, qui seront héritées par les classes filles.
- Il est également possible de fournir un constructeur aux classes scellées, qui sera appelé par les constructeurs des classes filles.
- Il est possible de définir des classes scellées à l’intérieur d’autres classes, pour créer des hiérarchies de classes scellées plus complexes.
- Il est possible de créer une classe scellée sans aucune classe fille, mais cela n’a généralement pas de sens, car une telle classe ne pourra jamais être instanciée.
Voici un exemple d’une classe scellée avec propriété, méthode et constructeur :
sealed class Shape(val color: String)
{
class Circle(radius: Double, color: String) : Shape(color)
{
val radius: Double = radius
fun area() = Math.PI * radius * radius
}
class Rectangle(val width: Double, val height: Double, color: String) : Shape(color)
{
fun area() = width * height
}
class Triangle(val base: Double, val height: Double, color: String) : Shape(color)
{
fun area() = base * height / 2
}
}
En utilisant les sealed class, vous pouvez créer des types de données plus robustes et fiables en restreignant les valeurs possibles et en garantissant que tous les cas possibles sont explicitement gérés.
J’ai appris récemment que ce concepte existait également en Go.
C’est une manière d’implémenté le type somme de plusieurs types. Un concepts que l’on retrouve beaucoup dans les langages fonctionnels.
Wikipédia m’a bien aidé sur la compréhension du sujet: https://fr.wikipedia.org/wiki/Type_alg%C3%A9brique_de_donn%C3%A9es#Type_somme
Une discution à ce sujet en Go (désolé j’aimerais avoir l’équivalent en Kotlin): https://zestedesavoir.com/forums/sujet/16769/interface-non-exportee/
Par-contre, je pensais que Kotlin était fonctionnel ? Un code comme celui-ci ne m’aurait pas étonné plutôt que des interfaces scellées.
“`
type SumType =
| New of Id: int
| Cancel of Id: int
“`