Paquetes En Kotlin

En este tutorial aprenderás a especificar paquetes en Kotlin con el objetivo de organizar estructuralmente a las declaraciones de tus programas (clases, funciones, propiedades, objetos, etc.). También verás cómo importar los elementos de dichos paquetes en diferentes archivos.

Declaración De Paquetes En Kotlin

La declaración de paquetes va en el inicio de un archivo fuente usando la sentencia package y luego el nombre del paquete al que pertenecerá el archivo.

Por ejemplo:

Supongamos que estamos creando un videojuego inspirado en Pac Man. Ahora imaginemos que diseñamos dos archivos Kotlin, uno para simular los fantasmas enemigos y otro para ejecutar la lógica principal del juego.

Para ello separamos ambos archivos en paquetes distintos. Para el archivo de fantasmas tendremos el paquete game.ghosts:

package game.ghosts

class Ghost() {
    var x = 0
    var y = 0
    fun move(){
        x++
        y++
    }
}

Y para el archivo principal el paquete game.main:

package game.main

fun main() {
    // Bucle del juego
}

La estructura de archivos sin embargo será la siguiente:

Ejemplo de paquetes en Kotlin

Como puedes observar, en Kotlin no es obligatorio hacer coincidir la estructura de directorios con las directivas de paquetes.

Esta convención va muy bien en proyectos de Kotlin puro, pero si tienes un proyecto con interoperabilidad entre Kotlin y Java, es mejor hacer coincidir los directorios con los paquetes.

Importaciones En Kotlin

Para importar un paquete desde un archivo Kotlin, usa la palabra clave import seguida del nombre completo de la entidad que deseas usar en el archivo, es decir, el nombre del paquete junto a los subpaquetes necesarios para llegar al elemento.

Por ejemplo, si deseamos importar la clase Ghost desde la función main(), entonces usamos la directiva import así:

package game.main

import game.ghosts.Ghost

fun main() {
    val ghost1 = Ghost()    
}

Importación Completamente Calificada

Otra forma de importar un elemento es usando su nombre calificado completo y omitir la sentencia import:

fun main() {
    val ghost1 = game.ghosts.Ghost()
}

Importar Todo El Contenido De Un Paquete

También es posible importar todos los elementos de un paquete usando la notación con estrella (*):

import game.ghosts.* // Todos las entidades que tenga ghosts

Importar Enumeraciones

Ya que los enumerados por lo general contienen múltiples constantes en su interior, al usarlas se usa un acceso calificado a la clase enumeración.

Por ejemplo, si el movimiento de los fantasmas estuviese dictaminado por una enum class para la dirección:

class Ghost() {
    var x = 0
    var y = 0

    enum class Direction {
        UP, DOWN, LEFT, RIGHT
    }

    fun move() {
        val randomDirection = Direction.values().random()
        when (randomDirection) {
            Direction.UP -> ++y
            Direction.DOWN -> --y
            Direction.LEFT -> --x
            Direction.RIGHT -> ++x
        }
    }
}

Podemos reemplazar el uso del nombre de Direction por una directiva import de la siguiente forma:

import game.ghosts.Ghost.Direction.*

El método resultaría así:

fun move() {
    val randomDirection = Direction.values().random()
    when (randomDirection) {
        UP -> ++y
        DOWN -> --y
        LEFT -> --x
        RIGHT -> ++x
    }
}

Solucionar Conflictos De Importación

Tomemos como ejemplo de un conflicto de importación el momento en que creamos una subclase de Ghost llamada Random. Su propósito es crear un fantasma con una posición aleatoria en el mapa.

import kotlin.random.Random

// ...

class Random:Ghost(){
    init {
        x = Random.nextInt(0,300)
        y = Random.nextInt(0,300)
    }
}

Ahora desde main.kt simulemos la creación simultánea de una instancia de un fantasma aleatorio y un número aleatorio con la clase Random del SDK de Java.

package game.main

import game.ghosts.Random


fun main() {
    val randomGhost = Random()
    val randomNumber = kotlin.random.Random.nextInt()
}

El compilador resolverá la inspección del conflicto a través de una importación calificada completamente para la clase usada en segundo lugar.

Para evitar este comportamiento introduce un alias de importación con la palabra clave as, luego de la directiva del import y junto a un nombre alternativo que desambigüe la colisión de nombres.

package game.main

import kotlin.random.Random
import game.ghosts.Random as RandomGhost


fun main() {
    val randomGhost = RandomGhost()
    val randomNumber = Random.nextInt()
}

En este caso, hemos utilizado el alias RandomGhost, resolviendo así el conflicto de importación entre game.ghosts.Random y kotlin.random.Random.

¿Ha sido útil esta publicación?