1. Co to jest wzorzec Singleton

Wzorzec Singleton to wzorzec projektowy kreacyjny, który zapewnia, że klasa ma tylko jedną instancję i udostępnia globalny punkt dostępu do tej instancji celem pobrania. Wzorzec Singleton jest powszechnie stosowany w scenariuszach, gdzie zasoby muszą być dzielone, lub dostęp do konkretnej instancji musi być kontrolowany.

2. Charakterystyka i Zalety wzorca Singleton

Wzorzec Singleton ma następujące cechy i zalety:

  • Zapewnia, że klasa ma tylko jedną instancję obiektu
  • Udostępnia globalny punkt dostępu dla zewnętrznego kodu do pobrania instancji
  • Unika powtarzającego się tworzenia instancji, co oszczędza zasoby systemu

3. Zastosowania wzorca Singleton

Wzorzec Singleton jest odpowiedni dla następujących scenariuszy zastosowań:

  • Rejestratory: Zapewnienie, że istnieje tylko jeden rejestrator dla całego systemu, aby zapobiec duplikacji logowania.
  • Pula połączeń do bazy danych: W środowiskach o dużej współbieżności, użycie wzorca Singleton może uniknąć częstego tworzenia i usuwania połączeń do bazy danych.

4. Implementacja wzorca Singleton w języku Golang

W języku Golang istnieją różne metody implementacji wzorca Singleton. Poniżej przedstawione są dwie powszechne metody implementacji.

4.1. Implementacja przy użyciu Leniwej Inicjalizacji i Wczesnej Inicjalizacji

Leniwa inicjalizacja tworzy obiekt instancji po raz pierwszy, gdy jest używany, podczas gdy wczesna inicjalizacja tworzy obiekt instancji przy starcie programu.

// Implementacja wzorca Singleton za pomocą leniwej inicjalizacji
package singleton

type Singleton struct {
}

var instance *Singleton

func GetInstance() *Singleton {
    if instance == nil {
        instance = &Singleton{}
    }
    return instance
}

// Implementacja wzorca Singleton za pomocą wczesnej inicjalizacji
package singleton

type Singleton struct {
}

var instance *Singleton = &Singleton{}

func GetInstance() *Singleton {
    return instance
}

4.2. Problemy z Bezpieczeństwem Wątków w Wzorcu Singleton

Powyższa metoda leniwej inicjalizacji może mieć problemy w środowisku wielowątkowym, ponieważ kilka wątków może jednocześnie wejść do warunku if instance == nil, co prowadzi do tworzenia wielu instancji.

4.3. Implementacja Wielowątkowej wersji wzorca Singleton za pomocą sync.Once

Użycie sync.Once zapewnia, że tylko jedna gorutyna wykonuje kod inicjalizacyjny, rozwiązując w ten sposób problem z bezpieczeństwem wątków.

// Implementacja wielowątkowej wersji wzorca Singleton za pomocą sync.Once
package singleton

import (
    "sync"
)

type Singleton struct {
}

var instance *Singleton
var once sync.Once

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

4.4. Implementacja Leniwej Inicjalizacji Wielowątkowej Wersji wzorca Singleton za pomocą sync.Mutex

Innym sposobem implementacji leniwej inicjalizacji wielowątkowej wersji wzorca Singleton jest użycie sync.Mutex, aby zablokować i zapewnić, że tylko jedna gorutyna wykonuje operację inicjalizacji.

// Implementacja leniwej inicjalizacji wielowątkowej wersji wzorca Singleton za pomocą sync.Mutex
package singleton

import (
    "sync"
)

type Singleton struct {
}

var instance *Singleton
var mu sync.Mutex

func GetInstance() *Singleton {
    if instance == nil {
        mu.Lock()
        defer mu.Unlock()
        if instance == nil {
            instance = &Singleton{}
        }
    }
    return instance
}