domingo, 25 de septiembre de 2022

Sealed classes de Kotlin: definición de jerarquías de clases restringidas


Veamos un ejemplo para entender mejor para que utilizar seald classess. La superclase Expr tiene dos subclases: Num, que representa un número; y Sum, que representa la suma de dos expresiones. Es conveniente manejar todas las subclases posibles en una expresión when. Pero tenemos que escribir el  else para especificar qué debería suceder si no tenemos coincidencias:


interface Expr

    class Num(val value: Int) : Expr

    class Sum(val left: Expr, val right: Expr) : Expr


fun eval(e: Expr): Int =

    when (e) {

        is Num -> e.value

        is Sum -> eval(e.right) + eval(e.left)

        else ->

            throw IllegalArgumentException("Unknown expression")

}


Cuando evalúas una expresión usando la construcción when, el compilador de Kotlin te obliga a especificar todas las opciones, pero nosotros sabemos que no es posible que haya otra opción. 

Tener que agregar siempre el else no es conveniente. Además, si agrega una nueva subclase, el compilador no detectará que algo ha cambiado y va a ir por el else. 

Kotlin proporciona una solución a este problema: Sealed classes  o clases selladas. Marcas una superclase con el modificador sellado, y eso restringe la posibilidad de crear subclases. Todas las subclases directas deben anidarse en la superclase:


sealed class Expr {

    class Num(val value: Int) : Expr()

    class Sum(val left: Expr, val right: Expr) : Expr()

}


fun eval(e: Expr): Int =

    when (e) {

        is Expr.Num -> e.value

        is Expr.Sum -> eval(e.right) + eval(e.left)

    }


Y listo!


El modificador sealed implica que la clase es abierta por lo tanto, no necesitamos agregar modificador open de forma explícita.

Otra cosa importante es que no puede declarar una interfaz sellada. ¿Por qué? Si pudiera, el compilador de Kotlin no podría garantizar que alguien no pueda implementar esta interfaz en el código Java.


No hay comentarios.:

Publicar un comentario