In Android App, per un oggetto che deve essere creato solo una volta e usato ovunque, usiamo il Singleton Pattern. Singleton Pattern è un pattern di progettazione software che limita l’istanza della classe a una sola istanza. Quindi, per implementare il Singleton pattern nel nostro progetto o software, creiamo una classe singleton. In questo blog, impareremo come fare una classe singleton in Kotlin? Quindi, cominciamo.
Classe singleton
Una classe singleton è una classe che è definita in modo tale che solo un’istanza della classe può essere creata e usata ovunque.
E’ usata dove abbiamo bisogno di una sola istanza della classe come NetworkService, DatabaseService, ecc.
Generalmente, è fatto perché ci vuole la risorsa del sistema per creare questi oggetti ancora e ancora. Quindi è meglio creare solo una volta e usare sempre lo stesso oggetto.
Proprietà della classe singleton
Seguono le proprietà di una tipica classe singleton:
- Una sola istanza: La classe singleton ha una sola istanza e questo viene fatto fornendo un’istanza della classe, all’interno della classe. Inoltre, alle classi esterne e alle sottoclassi dovrebbe essere impedito di creare l’istanza.
- Accessibile globalmente: L’istanza della classe singleton dovrebbe essere globalmente accessibile in modo che ogni classe possa usarla.
Regole per fare una classe Singleton
Per fare una classe Singleton si seguono le seguenti regole:
- Un costruttore privato
- Un riferimento statico della sua classe
- Un metodo statico
- Riferimento all’oggetto accessibile a livello globale
- Consistenza su più thread
Esempio di Singleton
Di seguito l’esempio di classe Singleton 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; }}
Quando si crea l’istanza per assicurare che non ci siano interferenze tra i thread, si usa la parola chiave synchronized.
Guardiamo il codice Kotlin per lo stesso. Di seguito è riportato il codice Kotlin per la classe Singleton:
object Singleton
Ok, cosa fare dopo questo?
Niente! Stai scherzando? No, questo è il codice per usare la classe Singleton in Kotlin. Molto semplice? Non preoccuparti, vediamo la spiegazione.
In Kotlin, dobbiamo usare la parola chiave object per usare la classe Singleton. La classe oggetto può avere funzioni, proprietà e il metodo init. Il metodo costruttore non è consentito in un oggetto, quindi possiamo usare il metodo init se è richiesta qualche inizializzazione e l’oggetto può essere definito all’interno di una classe. L’oggetto viene istanziato quando viene usato per la prima volta.
Facciamo un esempio della classe Singleton 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() }}
Qui, nell’esempio precedente, abbiamo una funzione chiamata printVarName() e una proprietà chiamata “variableName”. Quando una classe viene istanziata, allora i cambiamenti possono essere riflessi nella classe oggetto. Quindi, l’output del codice di cui sopra sarà:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Oggetto che estende una classe
Si può usare un oggetto in Kotlin per estendere qualche classe o implementare qualche interfaccia proprio come una classe normale. Facciamo un esempio dello stesso:
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) }}
E l’output del codice di cui sopra sarà:
I am in init of AI am in init of ASingleton class invoked.I am var
Quindi, puoi usare la classe oggetto proprio come una classe normale nella maggior parte dei casi.
Impara il System Design per la tua prossima intervista da qui.
Classe singleton con argomento in Kotlin
Nella parte precedente del blog, abbiamo imparato che non possiamo avere costruttori in una classe singleton. Per inizializzare qualcosa, possiamo farlo usando init nella classe singleton. Ma cosa succede se abbiamo bisogno di passare qualche argomento per l’inizializzazione proprio come nei costruttori parametrici? Poiché non possiamo usare i costruttori qui. Quindi, abbiamo bisogno di trovare qualche altro modo per fare lo stesso.
Se parliamo in particolare di Android, sappiamo che in Android abbiamo generalmente bisogno di passare un’istanza di contesto al blocco init di un singleton. Questo può essere fatto usando l’inizializzazione precoce e l’inizializzazione pigra. Nell’inizializzazione precoce, tutti i componenti sono inizializzati in Application.onCreate() usando le funzioni init(). Ma questo comporta un rallentamento dell’avvio dell’applicazione bloccando il thread principale. Quindi, si consiglia generalmente di utilizzare il modo di inizializzazione pigro. Nell’inizializzazione pigra, usiamo il contesto come argomento di una funzione che restituisce l’istanza del singleton. Possiamo ottenere questo utilizzando una classe SingletonHolder. Inoltre, per renderlo thread-safe, dobbiamo avere un modo di sincronizzazione e di bloccaggio a doppio controllo.
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 } } }}
Il codice di cui sopra è il codice più efficiente per il sistema di bloccaggio a doppio controllo e il codice è in qualche modo simile alla funzione lazy() in Kotlin ed è per questo che si chiama inizializzazione pigra. Quindi, ogni volta che volete una classe singleton con argomenti, allora potete usare la classe SingletonHolder.
Qui, nel codice sopra, al posto della funzione creatrice che viene passata come argomento al SingletonHolder, si può anche dichiarare una lambda personalizzata in linea o possiamo passare un riferimento al costruttore privato della classe singleton. Quindi, il codice sarà:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Ora, il singleton può essere facilmente invocato e inizializzato scrivendo il codice sottostante e questo è pigro e thread-safe 🙂
YourManager.getInstance(context).doSomething()
Questo è tutto per il blog Singleton. Spero che questo blog vi piaccia. Potete anche fare riferimento al sito web di Kotlin. Per saperne di più su alcuni degli argomenti più interessanti di Android, puoi visitare il nostro sito di blogging e unirti al nostro viaggio di apprendimento.
Continua a imparare 🙂
Team MindOrks!