Dans Android App, pour un objet qui doit être créé une seule fois et utilisé partout, nous utilisons le Singleton Pattern. Singleton Pattern est un modèle de conception de logiciel qui restreint l’instanciation de la classe à seulement « une » instance. Ainsi, pour mettre en œuvre le modèle singleton dans notre projet ou logiciel, nous créons une classe singleton. Dans ce blog, nous allons apprendre comment créer une classe singleton en Kotlin ? Alors, commençons.
Classe singleton
Une classe singleton est une classe qui est définie de telle sorte qu’une seule instance de la classe peut être créée et utilisée partout.
Elle est utilisée lorsque nous avons besoin d’une seule instance de la classe comme NetworkService, DatabaseService, etc.
Généralement, cela est fait parce que cela prend la ressource du système pour créer ces objets encore et encore. Il est donc préférable de ne créer qu’une seule fois et d’utiliser encore et encore le même objet.
Propriétés de la classe singleton
Voici les propriétés d’une classe singleton typique :
- Une seule instance : La classe singleton n’a qu’une seule instance et cela se fait en fournissant une instance de la classe, à l’intérieur de la classe. De plus, les classes et sous-classes externes doivent être empêchées de créer l’instance.
- Globalement accessible : L’instance de la classe singleton doit être globalement accessible afin que chaque classe puisse l’utiliser.
Règles pour faire une classe Singleton
Les règles suivantes sont suivies pour faire une classe Singleton :
- Un constructeur privé
- Une référence statique de sa classe
- Une méthode statique
- Une référence d’objet accessible globalement
- Consistance entre plusieurs threads
Exemple de Singleton
Voici l’exemple de la classe 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; }}
Lors de la création de l’instance pour s’assurer qu’il n’y a pas d’interférence entre les threads, nous utilisons le mot clé synchronisé.
Regardons le code Kotlin pour la même chose. Voici le code Kotlin pour la classe Singleton :
object Singleton
Ok, que faire après cela ?
Rien ! Vous plaisantez ? Non, c’est le code pour utiliser la classe Singleton en Kotlin. Très simple ? Ne vous inquiétez pas, regardons l’explication.
En Kotlin, nous devons utiliser le mot clé object pour utiliser la classe Singleton. La classe objet peut avoir des fonctions, des propriétés, et la méthode init. La méthode constructor n’est pas autorisée dans un objet donc nous pouvons utiliser la méthode init si une certaine initialisation est nécessaire et l’objet peut être défini à l’intérieur d’une classe. L’objet est instancié quand il est utilisé pour la première fois.
Voyons un exemple de la classe 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() }}
Ici, dans l’exemple ci-dessus, nous avons une fonction nommée printVarName() et une propriété nommée « variableName ». Quand une classe est instanciée, alors les changements peuvent être reflétés dans la classe objet. Ainsi, la sortie du code ci-dessus sera:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Objet étendant une classe
Vous pouvez utiliser un objet en Kotlin pour étendre une certaine classe ou implémenter une certaine interface tout comme une classe normale. Prenons un exemple de la même chose :
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) }}
Et le résultat du code ci-dessus sera :
I am in init of AI am in init of ASingleton class invoked.I am var
Donc, vous pouvez utiliser la classe objet comme une classe normale dans la plupart des cas.
Apprenez la conception de systèmes pour votre prochain entretien à partir d’ici.
Classe singleton avec Argument dans Kotlin
Dans la partie précédente du blog, nous avons appris que nous ne pouvons pas avoir de constructeurs dans une classe singleton. Pour initialiser quelque chose, nous pouvons le faire en utilisant init dans la classe singleton. Mais que faire si vous avez besoin de passer un argument pour l’initialisation, comme dans les constructeurs paramétrés ? Puisque nous ne pouvons pas utiliser les constructeurs ici. Donc, nous devons trouver une autre façon de faire la même chose.
Si nous parlons particulièrement d’Android, nous savons que dans Android, nous devons généralement passer une instance de contexte au bloc init d’un singleton. Cela peut être fait en utilisant l’initialisation précoce et l’initialisation paresseuse. Dans l’initialisation précoce, tous les composants sont initialisés dans l’Application.onCreate() en utilisant les fonctions init(). Mais cela a pour conséquence de ralentir le démarrage de l’application en bloquant le thread principal. Il est donc généralement conseillé d’utiliser l’initialisation paresseuse. Dans l’initialisation paresseuse, nous utilisons le contexte comme argument d’une fonction retournant l’instance du singleton. Nous pouvons y parvenir en utilisant une classe SingletonHolder. En outre, pour le rendre thread-safe, nous devons avoir un moyen de synchronisation et de verrouillage à double vérification.
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 } } }}
Le code ci-dessus est le code le plus efficace pour le système de verrouillage à double vérification et le code est en quelque sorte similaire à la fonction lazy() dans Kotlin et c’est pourquoi il est appelé initialisation paresseuse. Donc, chaque fois que vous voulez une classe singleton avec des arguments, alors vous pouvez utiliser la classe SingletonHolder.
Ici, dans le code ci-dessus, à la place de la fonction creator qui est passée comme argument au SingletonHolder, une lambda personnalisée peut également être déclarée en ligne ou nous pouvons passer une référence au constructeur privé de la classe singleton. Ainsi, le code sera:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Maintenant, le singleton peut être facilement invoqué et initialisé en écrivant le code ci-dessous et cela est paresseux ainsi que thread-safe 🙂
YourManager.getInstance(context).doSomething()
C’est tout pour le blog Singleton. J’espère que vous aimez ce blog. Vous pouvez également vous référer au site web de Kotlin. Pour en savoir plus sur certains des sujets cool d’Android, vous pouvez visiter notre site de blog et peut rejoindre notre voyage d’apprentissage.
Keep Learning 🙂
Team MindOrks!