Hiérarchies scellées
Fait partie de la section Programmation orientée objet du Journey Kotlin de Coddy. Leçon 34 sur 57.
Une classe ou une interface sealed possède un ensemble fermé de sous-classes directes, toutes déclarées dans le même package et le même module. Le compilateur connaît chacune d’elles, ce qui convient aux résultats ayant un nombre fixe de formes :
sealed interface Result
data class Success(val value: Int) : Result
data class Failure(val reason: String) : Result
fun parseAge(text: String): Result {
val n = text.toIntOrNull() ?: return Failure("not a number: $text")
return if (n in 0..150) Success(n) else Failure("out of range: $n")
}À l’intérieur de main :
println(parseAge("42"))
println(parseAge("abc"))
println(parseAge("200"))Sortie :
Success(value=42)
Failure(reason=not a number: abc)
Failure(reason=out of range: 200)Comme l’ensemble est fermé, un when sur un type scellé est exhaustif sans else. Si quelqu’un ajoute une sous-classe ultérieurement, chaque when de ce type cesse de compiler jusqu’à ce qu’il gère le nouveau cas, de sorte qu’aucun cas n’est oublié :
sealed interface Result
data class Success(val value: Int) : Result
data class Failure(val reason: String) : Result
fun describe(r: Result) = when (r) {
is Success -> "ok: ${r.value}"
is Failure -> "error: ${r.reason}"
}Dans main :
println(describe(Success(7)))
println(describe(Failure("timeout")))Sortie :
ok: 7
error: timeoutUn cas sans données est un data object : une instance unique avec un toString() lisible. Sa branche when n’a pas besoin de is, puisqu’il n’existe qu’une seule instance. Les autres cas peuvent être des classes de données, des objets ou des classes ordinaires :
sealed interface Command
data object Quit : Command
data class Move(val steps: Int) : Command
data class Say(val text: String) : Command
fun parse(line: String): Command = when {
line == "quit" -> Quit
line.startsWith("move ") -> Move(line.drop(5).toInt())
else -> Say(line)
}
fun run(c: Command) = when (c) {
Quit -> "bye"
is Move -> "moving ${c.steps}"
is Say -> "saying ${c.text}"
}À l’intérieur de main :
for (line in listOf("move 3", "hello", "quit")) {
val c = parse(line)
println("$c: ${run(c)}")
}Sortie :
Move(steps=3): moving 3
Say(text=hello): saying hello
Quit: byeÉnumération ou hiérarchie scellée ? Une énumération est un ensemble fixe d’instances uniques qui possèdent toutes les mêmes propriétés. Une hiérarchie scellée permet à chaque cas de transporter ses propres données, et un cas tel que Move peut avoir de nombreuses instances avec des valeurs différentes :
enum class Light { RED, YELLOW, GREEN } // même forme, une instance chacune
sealed interface Payment // chaque cas a ses propres données
data class Card(val number: String) : Payment
data class Transfer(val iban: String, val reference: String) : Payment
data object Cash : PaymentDéfi
FacileUn robot comprend les commandes de l’interface scellée Command : Move(steps), Turn(left), Report et Invalid(text), qui sont fournies. Complétez parse(line) : move 3 donne Move(3), turn left et turn right donnent Turn, report donne Report, et tout le reste, y compris un déplacement sans nombre valide, donne Invalid avec la ligne. Complétez ensuite Robot.execute(command) avec un when exhaustif et sans else. Le robot commence en (0, 0) orienté vers N (le nord correspond à y + 1, l’est à x + 1). Il renvoie moved to (0, 3), facing W, at (0, 3) facing W ou ignored.
Le code fourni analyse chaque ligne et affiche Move(steps=3) -> moved to (0, 3).
Votre code doit être placé dans Robot.kt, Parser.kt, Command.kt, Move.kt, Turn.kt, Report.kt et Invalid.kt. Main.kt contient le code fourni pour les entrées et sorties et ne peut pas être modifié.
Essayez vous-même
fun main() {
// Code d'entrée/sortie fourni : le laisser tel quel
val input = generateSequence(::readLine).toList()
val robot = Robot()
for (line in input) {
val command = parse(line)
println("$command -> ${robot.execute(command)}")
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Classes et objets
Travailler avec des fichiersDéfinir des classesConstructeurs primairesBlocs init et validationConstructeurs secondairesRécapitulatif - Carte de bibliothèque4Héritage
Classes ouvertes et sous-classesRedéfinition des membressuper et constructeursClasses abstraitesRécapitulatif – Annuaire du personnel7Classes spéciales
Classes de donnéesClasses EnumHiérarchies scelléesequals, hashCode, toStringRécapitulatif - Suivi des commandes2Propriétés et encapsulation
Accesseurs personnalisésModificateurs de visibilitéSetters privéslazy et lateinitRécapitulatif - Compte bancaire5Interfaces
Déclarer des interfacesMéthodes par défautInterfaces multiplesInterfaces en tant que typesRécapitulatif - Méthodes de paiement8Génériques
Fonctions génériquesClasses génériquesContraintes de typeVariance avec in et outRécapitulatif - File de priorité11Projet : Gestion de bibliothèque
Livres et membresEmprunter des livresEntraînez-vous par vous-même : Playground Kotlin