In Android-apps gebruiken we het Singleton-patroon voor een object dat slechts eenmaal hoeft te worden gemaakt en overal kan worden gebruikt. Het Singleton-patroon is een softwareontwerppatroon dat de instantiëring van de klasse beperkt tot slechts “één” instantie. Dus, om het Singleton patroon in ons project of software te implementeren, maken we een singleton klasse. In deze blog zullen we leren hoe je een singleton class maakt in Kotlin? Dus, laten we beginnen.
Singleton klasse
Een singleton klasse is een klasse die is gedefinieerd op een zodanige wijze dat slechts een instantie van de klasse kan worden gemaakt en overal gebruikt.
Het wordt gebruikt wanneer we slechts een instantie van de klasse, zoals NetworkService, DatabaseService, enz. nodig.
In het algemeen wordt dit gedaan omdat het de middelen van het systeem om deze objecten te creëren keer op keer kost. Het is dus beter om hetzelfde object slechts eenmaal te maken en steeds opnieuw te gebruiken.
Eigenschappen van een singleton-klasse
Volgende zijn de eigenschappen van een typische singleton-klasse:
- Slechts één instantie: De singleton klasse heeft slechts één instantie en dit wordt gedaan door een instantie van de klasse, binnen de klasse, te verstrekken. Ook moet worden voorkomen dat buitenklassen en subklassen de instantie maken.
- Globaal toegankelijk: De instantie van de singleton klasse moet globaal toegankelijk zijn, zodat elke klasse er gebruik van kan maken.
Regels voor het maken van een singleton klasse
De volgende regels worden gevolgd om een singleton klasse te maken:
- Een private constructor
- Een statische verwijzing van zijn klasse
- Een statische methode
- Globaal toegankelijke objectverwijzing
- Consistentie over meerdere threads
Singleton Voorbeeld
Hieronder volgt het voorbeeld van een Singleton klasse in 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; }}
Bij het maken van de instantie om er zeker van te zijn dat er geen thread interferentie is, gebruiken we het synchronized keyword.
Laten we eens kijken naar de Kotlin code voor hetzelfde. Hieronder staat de Kotlin code voor de Singleton klasse:
object Singleton
Ok, wat moeten we hierna doen?
Niets! Ben je gek? Nee, dat is de code voor het gebruik van de Singleton klasse in Kotlin. Heel eenvoudig? Maak je geen zorgen, laten we eens kijken naar de uitleg.
In Kotlin, moeten we het object sleutelwoord gebruiken om de Singleton klasse te gebruiken. De object klasse kan functies, eigenschappen, en de init methode hebben. De constructor methode is niet toegestaan in een object, dus we kunnen de init methode gebruiken als er een initialisatie nodig is en het object kan worden gedefinieerd in een klasse. Het object wordt geïnstantieerd wanneer het voor de eerste keer wordt gebruikt.
Laten we eens een voorbeeld van de Singleton klasse in 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() }}
Hier, in het bovenstaande voorbeeld, hebben we een functie met de naam printVarName() en een eigenschap met de naam “variabeleNaam”. Wanneer een klasse wordt geïnstantieerd, dan kunnen veranderingen worden weerspiegeld in de object klasse. Dus, de output van de bovenstaande code zal zijn:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Object dat een klasse uitbreidt
U kunt een object in Kotlin gebruiken om een klasse uit te breiden of een interface te implementeren, net als een normale klasse. Laten we eens een voorbeeld van hetzelfde:
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) }}
En de output van de bovenstaande code zal zijn:
I am in init of AI am in init of ASingleton class invoked.I am var
Dus, je kunt object klasse net als een normale klasse in de meeste gevallen gebruiken.
Leer Systeemontwerp voor uw volgende Interview vanaf hier.
Singleton klasse met Argument in Kotlin
In het eerdere deel van de blog, hebben we geleerd dat we geen constructors in een singleton klasse kunnen hebben. Om iets te initialiseren kunnen we dat doen door init te gebruiken in de singleton klasse. Maar wat als je een argument moet doorgeven voor initialisatie, net zoals in geparametriseerde constructors? Aangezien we hier geen constructors kunnen gebruiken. Dus moeten we een andere manier vinden om hetzelfde te doen.
Als we het in het bijzonder over Android hebben, weten we dat we in Android in het algemeen een context instantie moeten doorgeven aan het init-blok van een singleton. Dit kan worden gedaan met behulp van Early initialization en Lazy initialization. Bij vroege initialisatie worden alle componenten geïnitialiseerd in de Application.onCreate() met behulp van de init() functies. Maar dit resulteert in het vertragen van het opstarten van de applicatie door het blokkeren van de hoofddraad. Dus wordt over het algemeen aangeraden om de luie initialisatie manier te gebruiken. Bij lazy initialization gebruiken we de context als argument voor een functie die de instantie van de singleton teruggeeft. We kunnen dit bereiken door een SingletonHolder klasse te gebruiken. Om het thread-safe te maken, hebben we ook een manier van synchronisatie en double-checked locking nodig.
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 } } }}
De bovenstaande code is de meest efficiënte code voor double-checked locking system en de code lijkt op de een of andere manier op de lazy() functie in Kotlin en daarom wordt het lazy initialization genoemd. Dus, wanneer je een singleton klasse met argumenten wilt, kun je de SingletonHolder klasse gebruiken.
Hier, in de bovenstaande code, in plaats van de creator functie die als argument wordt doorgegeven aan de SingletonHolder, kan ook een aangepaste lambda inline worden gedeclareerd of we kunnen een verwijzing naar de private constructor van de singleton klasse doorgeven. Dus, de code wordt:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Nu kan de singleton eenvoudig worden aangeroepen en geïnitialiseerd door de onderstaande code te schrijven en dit is zowel lui als thread-safe 🙂
YourManager.getInstance(context).doSomething()
Dat is het voor de Singleton blog. Hopelijk vind je deze blog leuk. U kunt ook de Kotlin website raadplegen. Om meer te leren over een aantal van de coole onderwerpen van Android, kunt u terecht op onze blogging website en kan deelnemen aan onze reis van het leren.
Keep Learning 🙂
Team MindOrks!