Comment peut-on implémenter le modèle de conception Singleton dans le langage de programmation go?Singleton dans go
Répondre
Mis à part l'argument de savoir si ou non la mise en œuvre du modèle singleton est une bonne idée, voici une mise en œuvre possible:
package singleton
type single struct {
O interface{};
}
var instantiated *single = nil
func New() *single {
if instantiated == nil {
instantiated = new(single);
}
return instantiated;
}
single
et instantiated
sont privées, mais New()
est public. Ainsi, vous ne pouvez pas instancier directement single
sans passer par New()
et suivre le nombre d'instanciations avec le booléen privé instantiated
. Ajuster la définition de single
au goût.
Toutefois, comme plusieurs autres ont noted, ce n'est pas sûr pour les threads, sauf si vous initialisez uniquement votre singleton dans init()
. Une meilleure approche serait de tirer parti de sync.Once
pour faire le travail pour vous:
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
}
Voir aussi la suggestion de hasan j de penser juste d'un paquet comme un singleton. Enfin, considérons ce que les autres suggèrent: les singletons sont souvent un indicateur d'une mise en œuvre problématique.
N'ayant pas testé ce code, il me semble que vous ne pourrez obtenir une instance de single que la première fois que vous appellerez Nouveau(). Après cela, vous obtenez juste zéro. Si vous perdez la trace de votre instance et qu'elle est collectée, vous ne pouvez plus en créer. Ne voudriez-vous pas garder trace du pointeur sur l'instance de single et renvoyer celle-ci au lieu de zéro? –
D'accord; J'ai changé le code pour le faire, bien que linguistiquement, je ne suis pas très heureux avec New() retournant quelque chose d'autre qu'un nouvel objet. Dans une autre langue, j'aurais probablement levé une exception en essayant d'instancier l'objet une seconde fois. Notez qu'avec cette approche, le singleton ne sortira jamais de sa portée. – esm
Aussi, je rappellerai encore qu'une meilleure façon de penser à ceci est probablement l'approche Pythonic de hasen j: traitez un paquet comme votre singleton, ce que le langage impose déjà pour vous. – esm
Avant d'essayer de trouver un moyen de se plier à votre volonté Allez, vous voudrez peut-être jeter un oeil à certains articles:
En résumé, plus de temps que les gens ont trouvé singletons d'être optimales, et à mon avis surtout si vous essayez de faire tout développement piloté par les tests: à plusieurs niveaux, ils sont à peu près aussi mauvais que mondial variables
[Avertissement: Je sais que ce ne est pas une réponse stricte à votre question, mais il est vraiment pertinent]
La philosophie Unix (petits outils pointus) n'est-elle pas similaire à l'utilisation de classes Singleton? – Gustav
Il suffit de mettre vos variables et fonctions au niveau du package.
Voir aussi la même question: How to make a singleton in Python
tout simplement avoir une seule statique, finale, constante, globale, à l'échelle d'instance d'application de l'objet que vous voulez.
Ceci contredit cependant le paradigme OO. Son utilisation devrait être limitée aux primitives et aux objets immuables, pas aux objets mutables.
Il ne fait que contredire ce que les écoles Java enseignent à propos de OO – hasen
Vous pouvez faire l'initialisation à l'aide du once package:
Cela garantira que vos méthodes d'initialisation ne s'appellent une fois.
Il n'y a pas de paquetage unique. Je suppose qu'il a été retiré? –
puisque GO1 est sync: http://golang.org/pkg/sync/#example_Once – fabrizioM
Je pense que dans un monde en même temps, nous devons être un peu plus conscient que ces lignes ne sont pas exécutées atomiquement:
if instantiated == nil {
instantiated = new(single);
}
je suivrais la suggestion de @marketer et utiliser le package « synchronisation »
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
}
une raison pour laquelle vous ajoutez les variables non exportées avec '_'? – Brenden
Habitude, j'imagine. –
Bonjour @fabrizioM, j'ai une question ici: votre code est thread-safe. Mais il y a un autre problème: le nom de la structure est MySingleton - donc nous pouvons init un objet sans appeler New(): secondInstance: = MySingleton {}. – hungson175
La meilleure approche sera:
package singleton
import "sync"
type singleton struct {
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
Vous devriez lire Link
Vous devez être conscient que Once.Do
est sérieux au sujet de l'exécution du code qu'une seule fois. Cela signifie, le code est toujours exécuté qu'une seule fois, même si elle aurait pu paniquer:
de https://golang.org/pkg/sync/#Once.Do
Si f (note: la logique une fois) paniques, Do estime avoir retourné; les futurs appels de Do reviennent sans appeler f.
J'ai utilisé mutex au lieu d'assurer l'initialisation unique d'une variable de configuration globale pour surmonter cette restriction:
comment voulez-vous mettre en œuvre un Singleton dans toutes les langues? : D –
Espérons que c'est impossible. –
pourquoi le bourru avec singletons? Est-ce que je rate une nouvelle tendance? Le motif de conception singleton a ses utilisations. – Brenden