W Android App, dla obiektu, który jest wymagany do utworzenia tylko raz i używać wszędzie, używamy Singleton Pattern. Singleton Pattern jest wzorcem projektowym oprogramowania, który ogranicza instancję klasy do tylko „jednej” instancji. Tak więc, aby zaimplementować wzorzec Singleton w naszym projekcie lub oprogramowaniu, tworzymy klasę singleton. W tym blogu, dowiemy się, jak zrobić klasę singleton w Kotlinie? Więc, zaczynajmy.
Klasa singleton
Klasa singleton jest klasą, która jest zdefiniowana w taki sposób, że tylko jedna instancja klasy może być utworzona i używana wszędzie.
Jest używany, gdy potrzebujemy tylko jednej instancji klasy jak NetworkService, DatabaseService, itp.
Generalnie, jest to zrobione, ponieważ zajmuje zasoby systemu, aby utworzyć te obiekty ponownie i ponownie. Więc lepiej jest tworzyć tylko raz i używać ponownie tego samego obiektu.
Właściwości klasy singleton
Następujące są właściwości typowej klasy singleton:
- Tylko jedna instancja: Klasa singleton ma tylko jedną instancję i odbywa się to poprzez dostarczenie instancji klasy, wewnątrz klasy. Należy również uniemożliwić klasom zewnętrznym i podklasom tworzenie instancji.
- Globalnie dostępne: Instancja klasy singleton powinna być globalnie dostępna, aby każda klasa mogła z niej korzystać.
Reguły tworzenia klasy Singleton
Aby utworzyć klasę Singleton, należy przestrzegać następujących reguł:
- Prywatny konstruktor
- Statystyczna referencja swojej klasy
- Jedna statyczna metoda
- Globalnie dostępna referencja obiektu
- Skonsekwencja w wielu wątkach
Przykład Singletona
Poniżej przedstawiono przykład klasy Singleton w 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; }}
Podczas tworzenia instancji, aby zapewnić brak ingerencji wątków, używamy słowa kluczowego synchronized.
Spójrzmy na kod Kotlina dla tego samego. Poniżej znajduje się kod Kotlina dla klasy Singleton:
object Singleton
Ok, co zrobić po tym?
Nic! Czy ty sobie żartujesz? Nie, to jest kod do użycia klasy Singleton w Kotlinie. Bardzo proste? Nie martw się, spójrzmy na wyjaśnienie.
W Kotlinie, musimy użyć słowa kluczowego object, aby użyć klasy Singleton. Klasa obiektowa może mieć funkcje, właściwości i metodę init. Metoda konstruktora nie jest dozwolona w obiekcie, więc możemy użyć metody init, jeśli wymagana jest jakaś inicjalizacja i obiekt może być zdefiniowany wewnątrz klasy. Obiekt zostaje zainicjowany, gdy jest używany po raz pierwszy.
Miejmy przykład klasy Singleton w 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() }}
Tutaj, w powyższym przykładzie, mamy jedną funkcję o nazwie printVarName() i jedną właściwość o nazwie „variableName”. Kiedy klasa A jest instancjonowana, wtedy zmiany mogą być odzwierciedlone w klasie obiektu. Tak więc, wyjście z powyższego kodu będzie:
Singleton class invoked.I am VarClass init method. Singleton variableName property : New NameNew Name
Obiekt rozszerzający klasę
Możesz użyć obiektu w Kotlinie, aby rozszerzyć jakąś klasę lub zaimplementować jakiś interfejs, tak jak normalna klasa. Przykładem niech będzie:
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) }}
A wyjście powyższego kodu będzie:
I am in init of AI am in init of ASingleton class invoked.I am var
Więc, możesz używać klasy obiektów tak jak normalnej klasy w większości przypadków.
Learn System Design for your next Interview from here.
Singleton class with Argument in Kotlin
We wcześniejszej części bloga, dowiedzieliśmy się, że nie możemy mieć konstruktorów w klasie singleton. Aby coś zainicjalizować, możemy to zrobić za pomocą init w klasie singleton. Ale co jeśli potrzebujemy przekazać jakiś argument do inicjalizacji, tak jak w sparametryzowanych konstruktorach? Ponieważ nie możemy tutaj użyć konstruktorów. Więc, musimy znaleźć jakiś inny sposób na zrobienie tego samego.
Jeśli szczególnie mówimy o Androidzie, wiemy, że w Androidzie generalnie musimy przekazać instancję kontekstu do bloku init klasy singleton. Można to zrobić za pomocą wczesnej inicjalizacji i leniwej inicjalizacji. W przypadku wczesnej inicjalizacji, wszystkie komponenty są inicjalizowane w Application.onCreate() przy użyciu funkcji init(). Powoduje to jednak spowolnienie uruchamiania aplikacji poprzez blokowanie głównego wątku. Tak więc, generalnie zaleca się używanie leniwej inicjalizacji. W leniwej inicjalizacji, używamy kontekstu jako argumentu do funkcji zwracającej instancję singletonu. Możemy to osiągnąć poprzez użycie klasy SingletonHolder. Ponadto, aby uczynić go bezpiecznym dla wątków, musimy mieć sposób na synchronizację i podwójnie sprawdzane blokowanie.
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 } } }}
Powyższy kod jest najbardziej wydajnym kodem dla podwójnie sprawdzanego systemu blokowania i kod jest w jakiś sposób podobny do funkcji lazy() w Kotlinie i dlatego jest nazywany leniwą inicjalizacją. Tak więc, gdy chcesz mieć klasę singleton z argumentami, możesz użyć klasy SingletonHolder.
Tutaj, w powyższym kodzie, w miejsce funkcji Creator, która jest przekazywana jako argument do SingletonHolder, niestandardowa lambda może być również zadeklarowana inline lub możemy przekazać referencję do prywatnego konstruktora klasy singleton. Więc, kod będzie:
class YourManager private constructor(context: Context) { init { // do something with context } companion object : SingletonHolder<YourManager, Context>(::YourManager)}
Teraz, singleton może być łatwo wywołany i zainicjalizowany przez napisanie poniższego kodu i jest to zarówno leniwe jak i bezpieczne dla wątków 🙂
YourManager.getInstance(context).doSomething()
To jest to dla Singleton blog. Mam nadzieję, że podoba Ci się ten blog. Możesz również odnieść się do strony internetowej Kotlin. Aby dowiedzieć się więcej o niektórych z fajnych tematów Android, można odwiedzić naszą stronę internetową blogów i może dołączyć do naszej podróży nauki.
Keep Learning 🙂
Team MindOrks!