Domanda

Come si implementa il modello di progettazione Singleton nel linguaggio di programmazione go?

È stato utile?

Soluzione

Mettendo da parte l'argomento se l'implementazione del pattern singleton sia una buona idea, ecco una possibile implementazione:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

func New() *single {
        if instantiated == nil {
                instantiated = new(single);
        }
        return instantiated;
}

single e istanziati sono privati, ma New () è pubblico. Pertanto, non è possibile creare un'istanza diretta di single senza passare attraverso New () e tiene traccia del numero di istanze con il istanziato booleano privato. Modifica la definizione di single a piacere.

Tuttavia, come molti altri hanno annotato , questo non è thread-safe, a meno che tu non stia inizializzando il tuo singleton in init () . Un approccio migliore sarebbe quello di sfruttare sync.Once per fare il duro lavoro per te:

package singleton

import "sync"

type single struct {
        O interface{};
}

var instantiated *single
var once sync.Once

func New() *single {
        once.Do(func() {
                instantiated = &single{}
        })
        return instantiated
}

Vedi anche, il suggerimento di hasan j di pensare solo a un pacchetto come un singleton. E infine, considera ciò che gli altri suggeriscono: che i singoli sono spesso un indicatore di un'implementazione problematica.

Altri suggerimenti

Prima di provare a trovare un modo per piegare Vai alla tua volontà, potresti dare un'occhiata ad alcuni articoli:

In breve, nel tempo le persone hanno scoperto che i singoli non sono ottimali e imho specialmente se stai cercando di fare uno sviluppo guidato dai test: a molti livelli sono praticamente cattivi come variabili globali.

[disclaimer: so che non è una risposta rigorosa alla tua domanda ma è davvero pertinente]

Metti solo le tue variabili e funzioni a livello di pacchetto.

Vedi anche una domanda simile: Come creare un singleton in Python

Penso che in un mondo concorrente dobbiamo essere un po 'più consapevoli del fatto che queste linee non sono eseguite atomicamente:

if instantiated == nil {
    instantiated = new(single);
}

Seguirei il suggerimento di @marketer e utilizzerei il pacchetto " sync "

import "sync"

type MySingleton struct {

}

var _init_ctx sync.Once 
var _instance *MySingleton

func New() * MySingleton {
     _init_ctx.Do( func () { _instance = new(MySingleton) }  )
     return _instance 
}

L'approccio migliore sarà:

 package singleton

 import "sync"

 type singleton struct {
 }

 var instance *singleton
 var once sync.Once

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

Dovresti leggere questo Link

Puoi effettuare l'inizializzazione utilizzando il pacchetto una volta :

Questo assicurerà che i tuoi metodi init vengano chiamati una sola volta.

Basta avere un'unica istanza statica, finale, costante, globale, a livello di applicazione dell'oggetto desiderato.

Ciò tuttavia contraddice il paradigma OO. Il suo uso dovrebbe essere limitato ai primitivi e agli oggetti immutabili, non agli oggetti mutabili.

Dovresti essere consapevole che Once.Do è serio nell'esecuzione del codice una sola volta. Ciò significa che il codice viene sempre eseguito una sola volta, anche se potrebbe essere stato preso dal panico:

da https://golang.org/pkg/sync/#Once.Do

  

Se f (nota: la logica una volta) va nel panico, Do lo considera restituito; le chiamate future di Do ritornano senza chiamare f.

Ho usato invece i mutex per garantire l'inizializzazione unica di una variabile di configurazione globale per superare questa restrizione:

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top