Erstellen Sie ein Singleton in Kotlin

David Mbochi Njonge 20 Juni 2023
  1. Erstellen Sie ein Singleton mit der Kotlin-API
  2. Erstellen Sie ein Singleton mit einem Companion-Objekt
  3. Erstellen Sie ein Thread-sicheres Singleton mithilfe eines Companion-Objekts
  4. Erstellen Sie ein Singleton mit dem Lazy Initializer
  5. Abschluss
Erstellen Sie ein Singleton in Kotlin

Entwurfsmuster sind eine Reihe von Lösungen für häufig auftretende Probleme, die auf der Grundlage der jeweiligen Anforderung auftreten, und diese Lösungen können in anderen Systemen wiederverwendet werden, die versuchen, dasselbe Problem zu lösen. Es gibt verschiedene Entwurfsmuster, einschließlich schöpferischer, verhaltensbezogener und struktureller Entwurfsmuster.

Das Kreationsdesignmuster beschäftigt sich damit, wie Objekte erstellt werden, und in diesem Lernprogramm erfahren Sie, wie Sie das Singleton-Muster verwenden, das ein Beispiel für das Kreationsdesignmuster ist.

Das Singleton-Muster ist ein Entwurfsmuster, das dabei hilft, eine einzelne Kopie eines Objekts zu erstellen und einen einzigen Zugriffspunkt darauf bereitzustellen.

Bei der Entwicklung von Anwendungen gibt es Situationen, in denen wir eine einzelne Kopie eines Objekts benötigen, z. B. Objekte für Thread-Pools, Protokollierung, Gerätetreiber, Registrierungseinstellungen, Caches und andere.

Ein Programm mit mehreren Kopien dieser Objekte kann zu falschem Verhalten, Ressourcenüberbeanspruchung und inkonsistenten Ergebnissen führen. In diesem Tutorial lernen wir verschiedene Möglichkeiten kennen, wie wir ein Singleton in Kotlin erstellen können.

Erstellen Sie ein Singleton mit der Kotlin-API

Kotlin bietet ein Singleton, das wir sofort verwenden können, ohne Objekterstellungscode dafür schreiben zu müssen. Um dies zu erreichen, müssen wir unseren Singleton-Namen mit dem Schlüsselwort object definieren, und innerhalb dieses Singletons können wir beliebige Member-Variablen und Funktionen hinzufügen.

Öffnen Sie IntelliJ und wählen Sie Datei > Neu > Projekt. Geben Sie im sich öffnenden Fenster den Projektnamen als kotlin-singleton ein, wählen Sie Kotlin im Abschnitt Sprache und Intellij im Abschnitt Build-System aus.

Drücken Sie abschließend die Schaltfläche Erstellen, um das Projekt zu generieren.

Erstellen Sie eine Datei namens Main.kt im Ordner src/main/kotlin und kopieren Sie den folgenden Code und fügen Sie ihn in die Datei ein.

object Singleton{
    fun showMessage(): Singleton {
        return Singleton
    }
}

fun main(){
    println(Singleton.showMessage())
    println(Singleton.showMessage())
}

Wie oben erwähnt, ist dies die Standardmethode zum Erstellen eines Singletons in Kotlin und sehr einfach zu implementieren. Beachten Sie, dass das erstellte Singleton-Objekt Thread-sicher ist, was bedeutet, dass selbst Multithread-Programme kein neues Objekt erstellen können, was zu Dateninkonsistenzen führen kann.

In diesem Code haben wir ein Singleton mit dem Namen Singleton und eine Member-Funktion namens showMessage() erstellt. Die Funktion gibt den Verweis auf das erstellte Singleton zurück.

Führen Sie diesen Code aus und beachten Sie, dass die beiden Aufrufe der Memberfunktion einen Verweis auf dasselbe Objekt zurückgeben, wie unten gezeigt.

Singleton@5305068a
Singleton@5305068a

Erstellen Sie ein Singleton mit einem Companion-Objekt

Kommentieren Sie das vorherige Beispiel aus und kopieren Sie den folgenden Code und fügen Sie ihn nach dem Kommentar in die Datei Main.kt ein.

class Singleton private constructor(){
    companion object{
        var singleton = Singleton();
        fun getInstance(): Singleton{
            if (singleton == null){
                singleton = Singleton();
            }
            return singleton;
        }
    }
}


fun main(){
    println(Singleton.getInstance());
    println(Singleton.getInstance());
}

Der einzige Unterschied zwischen dem vorherigen und diesem Beispiel besteht darin, dass das Begleitobjekt innerhalb einer Klasse verwendet wird. Alle statischen Variablen und Funktionen in Kotlin werden innerhalb des Begleitobjekts platziert.

In diesem Code haben wir eine Methode namens getInstance() erstellt, die sicherstellt, dass nur eine Kopie des Objekts erstellt wird. Um sicherzustellen, dass dies eingehalten wird, machen wir den constructor() privat und prüfen, ob ein Objekt existiert, bevor wir eines erstellen.

Beachten Sie, dass dieser Ansatz gut funktioniert, aber nicht Thread-sicher ist. Wenn eine Anwendung multithreaded ist, kann sie gleichzeitig auf die Methode getInstance() zugreifen, was zu mehreren Objekten führt, die zu den zuvor erwähnten Problemen führen können.

Der nächste Abschnitt zeigt, wie Sie den Singleton-Thread sicher machen.

Führen Sie diesen Code aus und stellen Sie sicher, dass die Ausgabe einen Verweis auf dasselbe unten gezeigte Objekt zurückgibt.

Singleton@1f32e575
Singleton@1f32e575

Erstellen Sie ein Thread-sicheres Singleton mithilfe eines Companion-Objekts

Kommentieren Sie den vorherigen Code aus und kopieren Sie den folgenden Code und fügen Sie ihn nach dem Kommentar in die Datei Main.kt ein.

class Singleton private constructor(){
    companion object{

        private var singleton = Singleton();

        @Synchronized
        fun getInstance(): Singleton{
            if (singleton == null){
                singleton = Singleton();
            }
            return singleton
        }
    }
}

Beachten Sie, dass dieser Code dem vorherigen Code ähnlich ist; Der einzige Unterschied besteht darin, dass wir die Annotation @Synchronized zur Methode getInstance() hinzugefügt haben.

Dieser Ansatz wird in Java als synchronisierte Methode bezeichnet. Gewindesicherung wird durch Sperren realisiert.

Objekte haben normalerweise Sperren, und wenn ein Thread die synchronisierte Methode erreicht, erwirbt er diese Sperre exklusiv, bis er das Erstellen eines Objekts abgeschlossen hat, was bedeutet, dass kein anderer Thread auf diese Methode zugreifen kann.

Wenn ein anderer Thread auf die Sperre zugreift, haben wir bereits ein Objekt, und der Thread verwendet den vorhandenen Thread, ohne einen neuen zu erstellen. Es gibt andere Möglichkeiten, eine Synchronisierung zu erreichen, z. B. die Verwendung des synchronisierten Blocks, der uns hilft, einen Abschnitt des Codes anstelle der gesamten Methode zu synchronisieren.

Beachten Sie, dass die Synchronisierung unsere Probleme löst, aber Leistungsprobleme in unserer Anwendung einführt. Die Synchronisation bewirkt, dass die Leistung unserer Anwendung um den Faktor 100 reduziert wird, und wir sollten ihre Verwendung überdenken, wenn unsere Anwendung leistungskritisch ist.

Wir können Ansätze verwenden, um von fauler Initialisierung zu eifriger Initialisierung, doppelt geprüftem Sperren zu wechseln oder es beizubehalten, wenn die Leistung die Anwendung nicht beeinträchtigt.

Erstellen Sie ein Singleton mit dem Lazy Initializer

Kommentieren Sie den vorherigen Code aus und kopieren Sie den folgenden Code und fügen Sie ihn nach dem Kommentar in die Datei Main.kt ein.

class Singleton{
    companion object{
        val singleton: Singleton by lazy {
            Singleton();
        }
    }

    fun showMessage(): Singleton {
        return Singleton.singleton
    }
}

fun main(){
    println(Singleton.singleton.showMessage())
    println(Singleton.singleton.showMessage())
}

In diesem Code haben wir mit der Funktion lazy() ein Singleton erstellt, das eine Thread-sichere Instanz von Lazy erstellt, indem es das Argument verwendet, das wir ihm übergeben. Es verwendet den LazyThreadSafetyMode.SYNCHRONIZED, um sicherzustellen, dass nur eine Sperre verwendet wird, um die Lazy-Instanz zu initialisieren.

Führen Sie diesen Code aus und stellen Sie sicher, dass die Ausgabe einen Verweis auf dasselbe unten gezeigte Objekt zurückgibt.

Singleton@3e3abc88
Singleton@3e3abc88

Abschluss

In diesem Tutorial haben wir die verschiedenen Möglichkeiten kennengelernt, mit denen wir ein Singleton-Objekt in Kotlin erstellen können. Zu den behandelten Ansätzen gehören die Verwendung des Schlüsselworts object, des companion object und der Funktion lazy initializer.

Mit der synchronisierten Methode haben wir auch gelernt, wie wir sicherstellen können, dass unser Singleton-Objekt Thread-sicher ist, wenn wir ein Begleitobjekt verwenden.

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub