2009-12-01 7 views
23

Comment peut-on implémenter le modèle de conception Singleton dans le langage de programmation go?Singleton dans go

+1

comment voulez-vous mettre en œuvre un Singleton dans toutes les langues? : D –

+26

Espérons que c'est impossible. –

+5

pourquoi le bourru avec singletons? Est-ce que je rate une nouvelle tendance? Le motif de conception singleton a ses utilisations. – Brenden

Répondre

25

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.

+0

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? –

+0

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

+0

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

15

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]

+0

La philosophie Unix (petits outils pointus) n'est-elle pas similaire à l'utilisation de classes Singleton? – Gustav

1

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.

+9

Il ne fait que contredire ce que les écoles Java enseignent à propos de OO – hasen

3

Vous pouvez faire l'initialisation à l'aide du once package:

Cela garantira que vos méthodes d'initialisation ne s'appellent une fois.

+0

Il n'y a pas de paquetage unique. Je suppose qu'il a été retiré? –

+1

puisque GO1 est sync: http://golang.org/pkg/sync/#example_Once – fabrizioM

7

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 
} 
+1

une raison pour laquelle vous ajoutez les variables non exportées avec '_'? – Brenden

+0

Habitude, j'imagine. –

+0

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

5

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

0

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: