„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Singleton-Entwurfsmuster

Singleton-Entwurfsmuster

Veröffentlicht am 30.07.2024
Durchsuche:881

Singleton Design Pattern

Das Singleton-Entwurfsmuster ist eines der wichtigsten und am häufigsten verwendeten in der Softwareprogrammierung. Es stellt sicher, dass eine Klasse während der Anwendungslaufzeit nur eine einzige Instanz hat, und stellt einen globalen Zugriffspunkt auf diese Instanz bereit. In diesem Artikel werden wir die Bedeutung von Singleton diskutieren, wie man es in Golang implementiert und welche Vorteile es mit sich bringt, insbesondere in gleichzeitigen Umgebungen.

Was ist Singleton?

Singleton ist ein Entwurfsmuster, das die Instanz einer Klasse auf eine einzelne Instanz beschränkt. Dies ist besonders nützlich in Situationen, in denen ein einzelner Kontrollpunkt oder eine einzelne gemeinsam genutzte Ressource erforderlich ist, wie zum Beispiel:

  • Konfigurationsmanager, bei denen Anwendungseinstellungen zentralisiert werden müssen.
  • Datenbankverbindungspools, in denen eine begrenzte Anzahl von Verbindungen effizient verwaltet werden muss.
  • Logger, bei denen die Protokollkonsistenz entscheidend ist.

Warum Singleton verwenden?

Ich werde einige Punkte zur Implementierung von Pattern auflisten, die sinnvoller sind und auch zeigen, dass nicht alles rosig ist, sondern einige der Probleme, die wir damit haben können.

Vorteile

  • Globale Konsistenz: Garantiert, dass alle Punkte der Anwendung dieselbe Instanz verwenden, wodurch Daten- und Verhaltenskonsistenz gewährleistet wird.
  • Zugriffskontrolle: Zentralisiert die Kontrolle über die Erstellung und den Zugriff auf die Instanz und erleichtert so die Wartung und Verwaltung des Lebenszyklus des Objekts.
  • Ressourceneffizienz: Vermeidet die unnötige Erstellung mehrerer Instanzen und spart so Speicher und Verarbeitungsressourcen.

Nachteile

  • Testschwierigkeit: Singletons können das Schreiben von Unit-Tests erschweren, da sie globale Zustände einführen, die verwaltet werden müssen.
  • Erhöhte Kopplung: Übermäßiger Einsatz von Singletons kann zu einer engeren Kopplung zwischen Komponenten führen, was die Wartung und Weiterentwicklung der Anwendung erschwert.

Implementierung eines Singletons

Um einen Singleton zu implementieren, verwende ich Golang. In dieser Sprache müssen wir besonders auf Parallelität achten, um sicherzustellen, dass nur eine Instanz erstellt wird, auch wenn mehrere Goroutinen gleichzeitig versuchen, auf die Instanz zuzugreifen.

Um unser Beispiel der realen Welt näher zu bringen, erstellen wir einen Logger für unsere Anwendung. Ein Logger ist ein gängiges Tool in Anwendungen, das eindeutig sein muss, um die Protokollkonsistenz sicherzustellen.

1 - Definieren der Struktur

Zuerst definieren wir die Struktur, in der wir eine einzelne Instanz haben möchten.

package logger

import (
    "fmt"
    "sync"
)

type Logger struct {}

var loggerInstance *Logger

2 – Implementierung der NewInstance-Funktion

Die NewInstance-Funktion ist für die Rückgabe der einzelnen Instanz der Singleton-Struktur verantwortlich. Wir verwenden einen Mutex, um die Sicherheit in gleichzeitigen Umgebungen zu gewährleisten, und implementieren doppelt überprüfte Sperren für Effizienz.

package logger

import (
    "fmt"
    "sync"
)

type Logger struct{}

var logger *Logger
var mtx = &sync.Mutex{}

func NewInstance() *Logger {
    if logger == nil {
        mtx.Lock()
        defer mtx.Unlock()
        if logger == nil {
            fmt.Println("Creating new Logger")
            logger = &Logger{}
        }
    } else {
        fmt.Println("Logger already created")
    }
    return logger
}

3 – Protokolltypen implementieren

Ein Protokolltool verfügt immer über einige Protokolltypen, z. B. „Info“, um nur die Informationen anzuzeigen, „Fehler“, um Fehler anzuzeigen usw. Auf diese Weise können Sie auch die Art der Informationen filtern, die wir in unserer Anwendung anzeigen möchten.

Erstellen wir also eine Methode, die unser Protokoll mit dem Info-Typ anzeigt. Dazu erstellen wir eine Funktion, die unsere Protokollnachricht empfängt und sie im INFO-Format formatiert.

package logger

import (
    "fmt"
    "sync"
    "time"
)

const (
    INFO    string = "INFO"
)

type Logger struct{}

var logger *Logger
var mtx = &sync.Mutex{}

func NewInstance() *Logger {
    if logger == nil {
        mtx.Lock()
        defer mtx.Unlock()
        if logger == nil {
            fmt.Println("Creating new logger")
            logger = &Logger{}
        }
    } else {
        fmt.Println("Logger already created")
    }
    return logger
}

func (l *Logger) Info(message string) {
    fmt.Printf("%s - %s: %s\n", time.Now().UTC().Format(time.RFC3339Nano), INFO, message)
}

4 – Verwendung des Loggers

Und um unseren neuen Logger zu verwenden, werden wir ihn in unserem Hauptpaket instanziieren und ein Protokoll erstellen, um zu sehen, wie diese Implementierung funktioniert.

package main

import (
    "playground-go/pkg/logger"
)

func main() {
    log := logger.NewInstance()
    log.Info("This is an example of log")
}

Das ist das Ergebnis, wenn wir das Programm ausführen:

Creating new logger
2024-07-03T19:34:57.609599Z - INFO: This is an example of log

Wenn wir testen möchten, ob NewInstance wirklich garantiert, dass nur eine Instanz ausgeführt wird, können wir den folgenden Test durchführen.

package main

import (
    "fmt"
    "playground-go/pkg/logger"
)

func main() {
    log := logger.NewInstance()
    log.Info("This is an example of log")

    log2 := logger.NewInstance()
    log2.Info("This is another example of log")

    if log == log2 {
        fmt.Println("same instance")
    } else {
        fmt.Println("different instance")
    }
}

Unsere Protokolle haben sich geändert und jetzt können wir sehen, dass wir die Erstellung einer neuen Instanz blockiert haben:

Creating new logger
2024-07-03T19:45:19.603783Z - INFO: This is an example of log
Logger already created
2024-07-03T19:45:19.603793Z - INFO: This is another example of log
same instance

Abschluss

Das Singleton-Muster ist ein leistungsstarkes Tool, um sicherzustellen, dass während der Anwendungslaufzeit nur eine Instanz einer bestimmten Klasse vorhanden ist. Im Logger-Beispiel haben wir gesehen, wie dieses Muster angewendet werden kann, um die Protokollkonsistenz in der gesamten Anwendung sicherzustellen.

Ich hoffe, das hilft Ihnen, Singleton in Golang besser zu verstehen.

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/rflpazini/singleton-design-pattern-1n51?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3