¿Cómo crear una clase Singleton en Kotlin?

¿Cómo crear una clase Singleton en Kotlin?

En la aplicación Android, para un objeto que se requiere que se cree una sola vez y se utilice en todas partes, utilizamos el patrón Singleton. El patrón Singleton es un patrón de diseño de software que restringe la instanciación de la clase a sólo «una» instancia. Por lo tanto, para implementar el patrón Singleton en nuestro proyecto o software, hacemos una clase singleton. En este blog, vamos a aprender cómo hacer una clase singleton en Kotlin? Así que, vamos a empezar.

Clase Singleton

Una clase singleton es una clase que se define de tal manera que sólo una instancia de la clase puede ser creada y utilizada en todas partes.

Se utiliza donde necesitamos sólo una instancia de la clase como NetworkService, DatabaseService, etc.

Generalmente, se hace porque toma el recurso del sistema para crear estos objetos una y otra vez. Así que es mejor crear sólo una vez y utilizar una y otra vez el mismo objeto.

Propiedades de la clase Singleton

Las siguientes son las propiedades de una típica clase singleton:

  1. Sólo una instancia: La clase singleton sólo tiene una instancia y esto se hace proporcionando una instancia de la clase, dentro de la clase. Además, se debe impedir que las clases externas y las subclases creen la instancia.
  2. Accesible globalmente: La instancia de la clase singleton debe ser globalmente accesible para que cada clase pueda utilizarla.

Reglas para hacer una clase Singleton

Se siguen las siguientes reglas para hacer una clase Singleton:

  1. Un constructor privado
  2. Una referencia estática de su clase
  3. Un método estático
  4. Referencia de objeto accesible globalmente
  5. Consistencia a través de múltiples hilos

Ejemplo de Singleton

A continuación se muestra el ejemplo de clase Singleton en java:

public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}

Al crear la instancia para asegurar que no haya interferencia de hilos, usamos la palabra clave synchronized.

Veamos el código Kotlin para lo mismo. A continuación se muestra el código Kotlin para la clase Singleton:

object Singleton

Ok, ¿qué hacer después de esto?

¡Nada! ¿Estás bromeando? No, ese es el código para usar la clase Singleton en Kotlin. ¿Muy sencillo? No te preocupes, veamos la explicación.

En Kotlin, necesitamos usar la palabra clave object para usar la clase Singleton. La clase object puede tener funciones, propiedades y el método init. El método constructor no está permitido en un objeto por lo que podemos utilizar el método init si se requiere alguna inicialización y el objeto puede ser definido dentro de una clase. El objeto se instancian cuando se utiliza por primera vez.

Vamos a tener un ejemplo de la clase Singleton en Kotlin.

object Singleton{ init { println("Singleton class invoked.") } var variableName = "I am Var" fun printVarName(){ println(variableName) }}fun main(args: Array<String>) { Singleton.printVarName() Singleton.variableName = "New Name" var a = A()}class A { init { println("Class init method. Singleton variableName property : ${Singleton.variableName}") Singleton.printVarName() }}

Aquí, en el ejemplo anterior, estamos teniendo una función llamada printVarName() y una propiedad llamada «variableName». Cuando una clase es instanciada, entonces los cambios pueden ser reflejados en la clase objeto. Así, la salida del código anterior será:

Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name

Objeto que extiende una clase

Puedes usar un objeto en Kotlin para extender alguna clase o implementar alguna interfaz al igual que una clase normal. Veamos un ejemplo de lo mismo:

fun main(args: Array<String>) { var a = A() Singleton.printVarName()}open class A { open fun printVarName() { print("I am in class printVarName") } init { println("I am in init of A") }}object Singleton : A() { init { println("Singleton class invoked.") } var variableName = "I am Var" override fun printVarName() { println(variableName) }}

Y la salida del código anterior será:

I am in init of AI am in init of ASingleton class invoked.I am var

Así que puedes usar la clase objeto igual que una clase normal en la mayoría de los casos.

Aprende diseño de sistemas para tu próxima entrevista desde aquí.

Clase singleton con argumento en Kotlin

En la parte anterior del blog, aprendimos que no podemos tener constructores en una clase singleton. Para inicializar algo, podemos hacerlo usando init en la clase singleton. ¿Pero qué pasa si necesitas pasar algún argumento para la inicialización como en los constructores parametrizados? Ya que aquí no podemos usar constructores. Por lo tanto, tenemos que encontrar alguna otra manera de hacer lo mismo.

Si hablamos particularmente de Android, sabemos que en Android generalmente necesitamos pasar una instancia de contexto al bloque init de un singleton. Esto se puede hacer usando Early initialization y Lazy initialization. En la inicialización temprana, todos los componentes se inicializan en el Application.onCreate() utilizando las funciones init(). Pero esto resulta en la ralentización del inicio de la aplicación al bloquear el hilo principal. Por lo tanto, generalmente se aconseja utilizar la forma de inicialización perezosa. En la inicialización perezosa, utilizamos el contexto como argumento de una función que devuelve la instancia del singleton. Podemos lograr esto utilizando una clase SingletonHolder. Además, para que sea seguro para los hilos, necesitamos tener una forma de sincronización y bloqueo de doble comprobación.

open class SingletonHolder<out T: Any, in A>(creator: (A) -> T) { private var creator: ((A) -> T)? = creator @Volatile private var instance: T? = null fun getInstance(arg: A): T { val checkInstance = instance if (checkInstance != null) { return checkInstance } return synchronized(this) { val checkInstanceAgain = instance if (checkInstanceAgain != null) { checkInstanceAgain } else { val created = creator!!(arg) instance = created creator = null created } } }}

El código anterior es el código más eficiente para el sistema de bloqueo de doble comprobación y el código es de alguna manera similar a la función lazy() en Kotlin y por eso se llama inicialización perezosa. Así que, siempre que quieras una clase singleton con argumentos entonces puedes usar la clase SingletonHolder.

Aquí, en el código anterior, en lugar de la función creator que se pasa como argumento al SingletonHolder, también se puede declarar un lambda personalizado en línea o podemos pasar una referencia al constructor privado de la clase singleton. Por lo tanto, el código será:

class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}

Ahora, el singleton puede ser fácilmente invocado e inicializado escribiendo el código de abajo y esto es perezoso, así como a prueba de hilos 🙂

YourManager.getInstance(context).doSomething()

Eso es todo para el blog de Singleton. Espero que te guste este blog. También puedes consultar el sitio web de Kotlin. Para aprender más sobre algunos de los temas interesantes de Android, puede visitar nuestro sitio web de blogs y puede unirse a nuestro viaje de aprendizaje.

Sigue aprendiendo 🙂

¡Equipo MindOrks!

Deja un comentario