În aplicația Android, pentru un obiect care trebuie să fie creat o singură dată și utilizat peste tot, folosim modelul Singleton. Singleton Pattern este un model de proiectare software care restricționează instanțierea clasei la o singură instanță „unică”. Astfel, pentru a implementa modelul Singleton în proiectul sau software-ul nostru, creăm o clasă singleton. În acest blog, vom învăța cum să creăm o clasă singleton în Kotlin? Așadar, să începem.
Clasa Singleton
O clasă singleton este o clasă care este definită în așa fel încât o singură instanță a clasei poate fi creată și utilizată peste tot.
Este utilizată atunci când avem nevoie de o singură instanță a clasei, cum ar fi NetworkService, DatabaseService, etc.
În general, se face pentru că este nevoie de resursa sistemului pentru a crea aceste obiecte din nou și din nou. Deci, este mai bine să se creeze o singură dată și să se folosească din nou și din nou același obiect.
Proprietăți ale clasei singleton
Cele ce urmează sunt proprietățile unei clase singleton tipice:
- O singură instanță: Clasa singleton are o singură instanță și acest lucru se realizează prin furnizarea unei instanțe a clasei, în cadrul clasei. De asemenea, clasele exterioare și subclasele ar trebui să fie împiedicate să creeze instanța.
- Accesibilă la nivel global: Instanța clasei singleton trebuie să fie accesibilă la nivel global, astfel încât fiecare clasă să o poată utiliza.
Reguli de creare a unei clase Singleton
Pentru a crea o clasă Singleton se respectă următoarele reguli:
- Un constructor privat
- O referință statică a clasei sale
- O singură metodă statică
- Referință de obiect accesibilă la nivel global
- Consistență pe mai multe fire de execuție
Exemplu de Singleton
În continuare este prezentat un exemplu de clasă Singleton în 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 momentul creării instanței, pentru a ne asigura că nu există interferențe între firele de execuție, folosim cuvântul cheie synchronized.
Să ne uităm la codul Kotlin pentru același lucru. Mai jos este codul Kotlin pentru clasa Singleton:
object Singleton
Ok, ce să facem după asta?
Nimic! Glumiți? Nu, acesta este codul pentru utilizarea clasei Singleton în Kotlin. Foarte simplu? Nu vă faceți griji, haideți să ne uităm la explicație.
În Kotlin, trebuie să folosim cuvântul cheie object pentru a folosi clasa Singleton. Clasa obiect poate avea funcții, proprietăți și metoda init. Metoda constructor nu este permisă într-un obiect, așa că putem folosi metoda init dacă este necesară o anumită inițializare, iar obiectul poate fi definit în interiorul unei clase. Obiectul este instanțiat atunci când este utilizat pentru prima dată.
Vă prezentăm un exemplu de clasă Singleton în 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() }}
Aici, în exemplul de mai sus, avem o funcție numită printVarName() și o proprietate numită „variableName”. Atunci când o clasă este instanțiată, atunci modificările pot fi reflectate în clasa obiect. Astfel, rezultatul codului de mai sus va fi:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Obiect care extinde o clasă
Puteți utiliza un obiect în Kotlin pentru a extinde o clasă sau pentru a implementa o interfață la fel ca o clasă normală. Să avem un exemplu în acest sens:
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) }}
Și rezultatul codului de mai sus va fi:
I am in init of AI am in init of ASingleton class invoked.I am var
Deci, puteți utiliza clasa obiect la fel ca o clasă normală în majoritatea cazurilor.
Învățați de aici proiectarea sistemului pentru următorul interviu.
Clasa singleton cu argument în Kotlin
În partea anterioară a blogului, am învățat că nu putem avea constructori într-o clasă singleton. Pentru a inițializa ceva, putem face acest lucru folosind init în clasa singleton. Dar ce se întâmplă dacă aveți nevoie să treceți un argument pentru inițializare, la fel ca în cazul constructorilor parametrici? Din moment ce nu putem folosi constructori aici. Deci, trebuie să găsim o altă modalitate de a face același lucru.
Dacă vorbim în special despre Android, știm că în Android trebuie, în general, să trecem o instanță de context la blocul init al unui singleton. Acest lucru se poate face folosind inițializarea timpurie și inițializarea leneșă. În inițializarea timpurie, toate componentele sunt inițializate în Application.onCreate() folosind funcțiile init(). Dar acest lucru duce la încetinirea pornirii aplicației prin blocarea firului principal. Așadar, în general, se recomandă utilizarea metodei de inițializare leneșă. În inițializarea leneșă, utilizăm contextul ca argument pentru o funcție care returnează instanța singletonului. Putem realiza acest lucru utilizând o clasă SingletonHolder. De asemenea, pentru a o face thread-safe, trebuie să avem o modalitate de sincronizare și de blocare cu dublă verificare.
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 } } }}
Codul de mai sus este cel mai eficient cod pentru sistemul de blocare cu dublă verificare și codul este cumva similar cu funcția lazy() din Kotlin și de aceea se numește inițializare leneșă. Așadar, ori de câte ori doriți o clasă singleton cu argumente, atunci puteți utiliza clasa SingletonHolder.
Aici, în codul de mai sus, în locul funcției creator care este trecută ca argument pentru SingletonHolder, se poate declara, de asemenea, un lambda personalizat inline sau putem trece o referință la constructorul privat al clasei singleton. Deci, codul va fi:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Acum, singletonul poate fi ușor de invocat și inițializat prin scrierea codului de mai jos, iar acest lucru este atât leneș, cât și sigur pentru fire de execuție 🙂
YourManager.getInstance(context).doSomething()
Asta este tot pentru blogul Singleton. Sper că vă place acest blog. Puteți consulta, de asemenea, site-ul web Kotlin. Pentru a afla mai multe despre unele dintre subiectele interesante din Android, puteți vizita site-ul nostru de blogging și vă puteți alătura călătoriei noastre de învățare.
Keep Learning 🙂
Team MindOrks!