I Android App bruger vi Singleton-mønsteret til et objekt, som kun skal oprettes én gang og bruges overalt, til et objekt. Singletonmønsteret er et softwaredesignmønster, der begrænser instantieringen af klassen til kun “én” instans. Så for at implementere Singleton-mønsteret i vores projekt eller software laver vi en singleton-klasse. I denne blog vil vi lære, hvordan man laver en singleton-klasse i Kotlin? Så lad os komme i gang.
Singleton Class
En singleton-klasse er en klasse, der er defineret på en sådan måde, at kun én instans af klassen kan oprettes og bruges overalt.
Det bruges, hvor vi kun har brug for én instans af klassen som NetworkService, DatabaseService osv.
Generelt set gøres det, fordi det tager systemets ressourcer at oprette disse objekter igen og igen. Så det er bedre kun at oprette én gang og bruge det samme objekt igen og igen.
Egenskaber for singleton-klassen
Følgende er egenskaberne for en typisk singleton-klasse:
- Kun én instans: Singleton-klassen har kun én instans, og det sker ved at levere en instans af klassen inden for klassen. Desuden skal ydre klasser og underklasser forhindres i at oprette instansen.
- Globalt tilgængelig: Instansen af singleton-klassen skal være globalt tilgængelig, så alle klasser kan bruge den.
Regler for at lave en klasse Singleton
Følgende regler følges for at lave en Singleton-klasse:
- En privat konstruktør
- En statisk reference til sin klasse
- En statisk metode
- Globalt tilgængelig objektreference
- Konsistens på tværs af flere tråde
Singleton Eksempel
Følgende er eksemplet på Singleton-klassen i 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; }}
Når vi opretter instansen for at sikre, at der ikke er nogen trådinterferens, bruger vi nøgleordet synkroniseret.
Lad os se på Kotlin-koden for det samme. Nedenfor er Kotlin-koden for Singleton-klassen:
object Singleton
Ok, hvad skal vi gøre efter dette?
Ingen! Er det en spøg? Nej, det er koden til brug af Singleton-klassen i Kotlin. Meget simpelt? Bare rolig, lad os se på forklaringen.
I Kotlin skal vi bruge nøgleordet object for at bruge Singleton-klassen. Objektklassen kan have funktioner, egenskaber og init-metoden. Konstruktørmetoden er ikke tilladt i et objekt, så vi kan bruge init-metoden, hvis der er behov for en vis initialisering, og objektet kan defineres inde i en klasse. Objektet bliver instantieret, når det bruges første gang.
Lad os få et eksempel på Singleton-klassen i 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() }}
Her i ovenstående eksempel har vi én funktion ved navn printVarName() og én egenskab ved navn “variableName”. Når En klasse er instantieret, så kan ændringer afspejles i objektklassen. Så resultatet af ovenstående kode vil være:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Objekt, der udvider en klasse
Du kan bruge et objekt i Kotlin til at udvide en klasse eller implementere en grænseflade ligesom en normal klasse. Lad os få et eksempel på det samme:
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) }}
Og resultatet af ovenstående kode vil være:
I am in init of AI am in init of ASingleton class invoked.I am var
Så du kan bruge objektklasse ligesom en normal klasse i de fleste tilfælde.
Lær System Design til dit næste interview herfra.
Singleton-klasse med argument i Kotlin
I den tidligere del af bloggen lærte vi, at vi ikke kan have konstruktører i en singleton-klasse. Hvis vi vil initialisere noget, kan vi gøre det ved at bruge init i singleton-klassen. Men hvad nu hvis man har brug for at videregive et eller andet argument til initialisering ligesom i parametrerede konstruktører? Da vi ikke kan bruge konstruktorer her. Så vi er nødt til at finde en anden måde at gøre det samme på.
Hvis vi især taler om Android, ved vi, at vi i Android generelt skal videregive en kontekstinstans til init-blokken i en singleton. Dette kan gøres ved hjælp af Early initialization og Lazy initialization. Ved tidlig initialisering initialiseres alle komponenterne i Application.onCreate() ved hjælp af init()-funktionerne. Men dette resulterer i en langsommere opstart af applikationen ved at blokere hovedtråden. Så det tilrådes generelt at bruge den dovne initialiseringsmåde. Ved doven initialisering bruger vi konteksten som et argument til en funktion, der returnerer instansen af singletonen. Vi kan opnå dette ved at bruge en SingletonHolder-klasse. For at gøre det trådsikkert skal vi også have en måde med synkronisering og dobbeltkontrolleret låsning.
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 } } }}
Overstående kode er den mest effektive kode til dobbeltkontrolleret låsesystem, og koden ligner på en måde lazy() funktionen i Kotlin, og det er derfor, den kaldes lazy initialization. Så når du ønsker en singleton-klasse med argumenter, kan du bruge SingletonHolder-klassen.
Her i ovenstående kode kan der i stedet for creator-funktionen, der overgives som et argument til SingletonHolder, også deklareres en brugerdefineret lambda inline, eller vi kan overgive en henvisning til singleton-klassens private konstruktør. Så koden vil være:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Nu kan singletonen nemt påkaldes og initialiseres ved at skrive nedenstående kode, og dette er doven såvel som trådsikker 🙂
YourManager.getInstance(context).doSomething()
Det var det for Singleton-bloggen. Håber du kan lide denne blog. Du kan også henvise til Kotlin-webstedet. Hvis du vil lære mere om nogle af de fede emner inden for Android, kan du besøge vores blogwebsted og kan deltage i vores læringsrejse.
Keep Learning 🙂
Team MindOrks!