La declaración de constantes y el uso de companion objects son conceptos importantes de Kotlin que sustituyen a los miembros estáticos convencionales de Java y las dificultades asociadas al cruzar las paradigmas de la programación orientada a objetos y la programación funcional.
Historia del asunto: En Java, las constantes generalmente se declaran como campos static final, y los métodos estáticos se utilizan para funciones de utilidad o de fábrica. En Kotlin, en lugar de static, se introducen object y companion object, y para las constantes en tiempo de compilación se usa la palabra clave const.
Problema: Es necesario declarar valores que no dependan de instancias de clase, así como organizar métodos de fábrica y estado estático sin romper la integridad del OOP.
Solución: Los objetos compañeras (companion object) se declaran dentro de una clase y permiten colocar miembros comunes para todas las instancias:
Ejemplo de código:
class MyClass { companion object { const val DEFAULT_LIMIT = 10 fun create(): MyClass = MyClass() } } val limit = MyClass.DEFAULT_LIMIT val instance = MyClass.create()
Características clave:
¿Puede un companion object tener múltiples instancias en una clase?
No, en una clase solo puede haber un companion object. Intentar declarar un segundo generará un error de compilación. Sin embargo, se permite cualquier número de métodos/properties dentro del companion object.
¿Se pueden inicializar variables lateinit dentro de un companion object?
No, porque las propiedades con const o las variables dentro de companion object deben ser inicializadas de inmediato o ser val/var con inicialización explícita. lateinit no está permitido para propiedades dentro del companion object.
¿Puede un companion object tener su propio nombre y cuándo se requiere esto?
Sí, el nombre del companion object se asigna explícitamente si se necesita acceder a él por nombre o, por ejemplo, implementar interfaces. En otros casos, es opcional. Ejemplo:
class Foo { companion object Factory { fun create(): Foo = Foo() } } val instance = Foo.Factory.create()
Toda la funcionalidad auxiliar y las variables globales del programa se colocan en companion object, usando var en lugar de val/const:
Pros:
Contras:
Sólo se utilizan constantes en tiempo de compilación (const val) y funciones puras dentro del companion object, todo lo mutable es o bien localizado o pasado a través de DI:
Pros:
Contras: