Singleton in go
-
22-07-2019 - |
Frage
Wie implementieren man das Singleton-Entwurfsmuster in unterwegs Programmiersprache?
Lösung
Abgesehen von der Argumentation, ob die Singletonmuster Umsetzung ist eine gute Idee, hier ist eine mögliche Implementierung:
package singleton
type single struct {
O interface{};
}
var instantiated *single = nil
func New() *single {
if instantiated == nil {
instantiated = new(single);
}
return instantiated;
}
single
und instantiated
sind privat, aber New()
ist öffentlich. So können Sie nicht direkt single
instanziiert ohne durch New()
zu gehen, und es verfolgt die Anzahl der Instanzen mit dem privaten boolean instantiated
. Stellen Sie die Definition von single
abschmecken.
Wie jedoch einige andere haben bemerkt , ist dies nicht Thread-sicher, es sei denn, Sie sind nur in init()
Ihre Singleton initialisiert. Ein besserer Ansatz wäre sync.Once
zu nutzen, die harte Arbeit für Sie tun:
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
}
Siehe auch Vorschlag der hasan j nur ein Paket zu denken wie ein Singleton. Und schließlich betrachten, was andere darauf hindeutet. Dass Singletons sind oft ein Indikator für eine problematische Umsetzung
Andere Tipps
Bevor Sie versuchen, einen Weg zu finden Gehen Sie zu Ihrem Willen zu beugen, könnten Sie einen Blick auf einige Artikel nehmen wollen:
Insgesamt im Laufe der Zeit Menschen Singletons haben festgestellt, weniger als optimal zu sein, und imho insbesondere , wenn Sie versuchen, jede Testgetriebene Entwicklung zu tun: auf vielen Ebenen sind sie so ziemlich so schlecht, wie globale Variablen.
[Disclaimer: Ich weiß, es ist nicht eine strenge Antwort auf Ihre Frage, aber es ist wirklich relevant]
Sie Ihre Variablen und Funktionen auf Paketebene setzen.
Siehe auch ähnliche Frage: Wie einen Singleton in Python machen
Ich denke, dass in einer gleichzeitigen Welt brauchen wir ein bisschen mehr darüber im Klaren sein, dass diese Zeilen nicht atomar ausgeführt werden:
if instantiated == nil {
instantiated = new(single);
}
würde ich den Vorschlag von @marketer folgen und das Paket „sync“ verwenden
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
}
Der beste Ansatz wird sein:
package singleton
import "sync"
type singleton struct {
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
Sie sollten lesen Sie Link-
Sie können die Initialisierung tun mit dem einmal Paket :
Dadurch wird sichergestellt, dass Ihre init Methoden nur einmal aufgerufen.
hat nur eine einzige statische, final, konstant, global, anwendungsweite Instanz des Objekts Sie wollen.
Dies ist jedoch im Widerspruch zu dem OO-Paradigma. Sein Gebrauch soll auf Primitiven und unveränderliche Objekte beschränkt werden, keine Gegenstände auf Mutable.
Sie sollten sich bewusst sein, dass Once.Do
den Code über die Ausführung nur einmal ernst. Das bedeutet, dass der Code immer nur einmal ausgeführt, obwohl sie in Panik geraten könnten:
https://golang.org/pkg/sync/#Once.Do
Wenn f (Anmerkung: die einmal Logik) gerät in Panik, hält Do sie zurückgekehrt sein; zukünftige Anrufe von Do Rückkehr ohne f aufrufen.
Ich habe mutexes statt einzigartige Initialisierung eines globalen Konfigurationsvariable, um sicherzustellen, diese Einschränkung zu überwinden: