30 - POO - enum class

En Kotlin tenemos otro tipo especial de clase que se las declara con las palabras claves enum class.

Se las utiliza para definir un conjunto de constantes.

Problema 1

Declarar una enum class con los nombres de naipes de la baraja inglesa.
Definir una clase carta que tenga una propiedad de la clase enum class.

Proyecto131 - Principal.kt

enum class TipoCarta{
    DIAMANTE,
    TREBOL,
    CORAZON,
    PICA
}

class Carta(val tipo: TipoCarta, val valor: Int) {

    fun imprimir() {
        println("Carta: $tipo y su valor es $valor")
    }
}

fun main(parametro: Array<String>) {
    val carta1 = Carta(TipoCarta.TREBOL, 4)
    carta1.imprimir()
}

Para declarar un enum class indicamos cada una de las constantes posibles que se podrán guardar:

enum class TipoCarta{
    DIAMANTE,
    TREBOL,
    CORAZON,
    PICA
}

La clase Carta tiene dos propiedades, la primera llamada tipo que es de el enum class TipoCarta y la segunda el valor de la carta:

class Carta(val tipo: TipoCarta, val valor: Int) {

El método imprimir muestra el contenido de la propiedad tipo y la propiedad valor:

    fun imprimir() {
        println("Carta: $tipo y su valor es $valor")
    }

En la función main creamos un objeto de la clase Carta y le pasamos en el primer parámetro alguna de las cuatro constantes definidas dentro del enum class TipoCarta:

fun main(parametro: Array<String>) {
    val carta1 = Carta(TipoCarta.TREBOL, 4)
    carta1.imprimir()
}

Propiedades en un enum class

Igual que las clases comunes las clases enum class pueden tener propiedades definidas en el constructor. Luego debemos indicar un valor para cada una de esas propiedades en las constantes definidas.

Problema 2

Declarar un enum class que represente las cuatro operaciones básicas, asociar a cada constante un String con el signo de la operación.
Definir una clase Operación que defina tres propiedades, las dos primeras deben ser los números y la tercera el tipo de operación.

Proyecto132 - Principal.kt

enum class TipoOperacion (val tipo: String) {
    SUMA("+"),
    RESTA("-"),
    MULTIPLICACION("*"),
    DIVISION("/")
}

class Operacion (val valor1: Int, val valor2: Int, val tipoOperacion: TipoOperacion) {

    fun operar() {
        var resultado: Int = 0
        when (tipoOperacion) {
            TipoOperacion.SUMA -> resultado = valor1 + valor2
            TipoOperacion.RESTA -> resultado = valor1 - valor2
            TipoOperacion.MULTIPLICACION -> resultado = valor1 * valor2
            TipoOperacion.DIVISION -> resultado = valor1 / valor2
        }
        println("$valor1 ${tipoOperacion.tipo} $valor2 es igual a $resultado")
    }
}

fun main(parametro: Array<String>) {
    val operacion1 = Operacion(10, 4, TipoOperacion.SUMA)
    operacion1.operar()
}

Hemos declarado la clase TipoOperación con cuatro constantes llamadas: SUMA, RESTA, MULTIPLICACION y DIVISION.
Cada constante tiene asociado entre paréntesis el valor de la propiedad tipo que es un String:

enum class TipoOperacion (val tipo: String) {
    SUMA("+"),
    RESTA("-"),
    MULTIPLICACION("*"),
    DIVISION("/")
}

Declaramos la clase Operacion que recibe dos enteros y un objeto de tipo TipoOperacion:

class Operacion (val valor1: Int, val valor2: Int, val tipoOperacion: TipoOperacion) {

El método operar según el valor almacenado en la propiedad tipoOperacion almacena en la variable resultado el valor respectivo:

    fun operar() {
        var resultado: Int = 0
        when (tipoOperacion) {
            TipoOperacion.SUMA -> resultado = valor1 + valor2
            TipoOperacion.RESTA -> resultado = valor1 - valor2
            TipoOperacion.MULTIPLICACION -> resultado = valor1 * valor2
            TipoOperacion.DIVISION -> resultado = valor1 / valor2
        }

Para imprimir el operador utilizado ("+", "-" etc.) podemos acceder a la propiedad tipo del objeto tipoOperacion:

        println("$valor1 ${tipoOperacion.tipo} $valor2 es igual a $resultado")

En la función main definimos un objeto de la clase Operacion y le pasamos los dos enteros a operar y el tipo de operación a efectuar:

fun main(parametro: Array<String>) {
    val operacion1 = Operacion(10, 4, TipoOperacion.SUMA)
    operacion1.operar()
}

Acotaciones

Otros dato importante que podemos extraer de un enum class es la posición de una constante en la enumeración mediante la propiedad ordinal:

enum class TipoOperacion (val tipo: String) {
    SUMA("+"),
    RESTA("-"),
    MULTIPLICACION("*"),
    DIVISION("/")
}

fun main(parametro: Array<String>) {
    val tipo1 = TipoOperacion.MULTIPLICACION
    println(tipo1)         // MULTIPLICACION
    println(tipo1.tipo)    // *
    println(tipo1.ordinal) // 2
}

Con la propiedad ordinal nos retorna la posición de la constante dentro del enum class (la primer constante ocupa la posición 0, la segunda la posición 1 y así sucesivamente)

Si necesitamos recorrer mediante un for todos las constantes contenidas en un enum class la sintaxis es la siguiente:

enum class TipoOperacion (val tipo: String) {
    SUMA("+"),
    RESTA("-"),
    MULTIPLICACION("*"),
    DIVISION("/")
}

fun main(parametro: Array<String>) {
    for(elemento in TipoOperacion.values()) {
        println(elemento)
    }
}

Mediante valueOf podemos pasar un String con una constante y nos retorna una referencia a dicha constante:

enum class TipoOperacion (val tipo: String) {
    SUMA("+"),
    RESTA("-"),
    MULTIPLICACION("*"),
    DIVISION("/")
}

fun main(parametro: Array<String>) {
    val tipo1 = TipoOperacion.valueOf("RESTA")
    println(tipo1)         // RESTA
    println(tipo1.tipo)    // -
    println(tipo1.ordinal) // 1
}

Como cada constante es un objeto podemos sobreescribir el método toString y hacer que retorne una cadena distinta al nombre de la constante:

enum class TipoOperacion (val tipo: String) {
    SUMA("+") {
        override fun toString() = "operación suma"
    },
    RESTA("-"){
        override fun toString() = "operación resta"
    },
    MULTIPLICACION("*"),
    DIVISION("/")
}

fun main(parametro: Array<String>) {
    val tipo1 = TipoOperacion.SUMA
    println(tipo1)         // operación suma
    println(tipo1.tipo)    // +
    println(tipo1.ordinal) // 0
}

Si necesitamos obtener una de las constantes de la enumeración en forma aleatoria, la sintaxis más sencilla es:

enum class TipoOperacion {
    SUMA,
    RESTA,
    MULTIPLICACION,
    DIVISION
}

fun main(parametro: Array<String>) {
    val operacion = TipoOperacion.values().random()
    print(operacion)
}

Problema propuesto

  • Definir un enum class almacenando como constante los nombres de varios países sudamericanos y como propiedad para cada país la cantidad de habitantes que tiene.
    Definir una variable de este tipo e imprimir la constante y la cantidad de habitantes de dicha variable.
Solución
Proyecto133

enum class Paises (val habitantes: Int) {
    BRASIL (202450649),
    COLOMBIA (50364000),
    PERU (31151643),
    VENEZUELA (31028337),
    CHILE (18261884),
    ECUADOR (16298217),
    BOLIVIA (10888000),
    PARAGUAY (6460000),
    URUGUAY (3372000)
}

fun main(parametro: Array<String>) {
    val pais1 = Paises.BRASIL
    println(pais1)
    println(pais1.habitantes)
}