Edit: À partir d'une autre question, j'ai fourni une réponse qui contient des liens vers de nombreuses questions / réponses sur les singletons: Plus d'informations sur les singletons ici:
J'ai donc lu le fil Singletons: un bon design ou une béquille?
Et l'argument fait toujours rage.
Je vois les singletons comme un modèle de conception (bon et mauvais).
Le problème avec Singleton n'est pas le Pattern mais plutôt les utilisateurs (désolé tout le monde). Tout le monde et leur père pensent qu'ils peuvent en appliquer un correctement (et d'après les nombreuses interviews que j'ai faites, la plupart des gens ne le peuvent pas). Aussi parce que tout le monde pense pouvoir implémenter un Singleton correct, ils abusent du Pattern et l'utilisent dans des situations qui ne sont pas appropriées (en remplaçant les variables globales par des Singletons!).
Les principales questions auxquelles il faut répondre sont donc:
- Quand devez-vous utiliser un Singleton
- Comment implémenter correctement un singleton
Mon espoir pour cet article est que nous puissions rassembler ensemble en un seul endroit (plutôt que d'avoir à rechercher sur Google et plusieurs sites) une source faisant autorité pour savoir quand (et ensuite comment) utiliser correctement un Singleton. Une liste d'anti-utilisations et de mauvaises implémentations courantes serait également appropriée, expliquant pourquoi elles ne fonctionnent pas et pour de bonnes implémentations, leurs faiblesses.
Alors lancez le ballon:
je vais tenir ma main et dire que c'est ce que j'utilise mais a probablement des problèmes.
J'aime le traitement du sujet par "Scott Myers" dans ses livres "Effective C ++"
Bonnes situations pour utiliser des singletons (pas beaucoup):
- Cadres de journalisation
- Pools de recyclage de fils
/*
* C++ Singleton
* Limitation: Single Threaded Design
* See: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
* For problems associated with locking in multi threaded applications
*
* Limitation:
* If you use this Singleton (A) within a destructor of another Singleton (B)
* This Singleton (A) must be fully constructed before the constructor of (B)
* is called.
*/
class MySingleton
{
private:
// Private Constructor
MySingleton();
// Stop the compiler generating methods of copy the object
MySingleton(MySingleton const& copy); // Not Implemented
MySingleton& operator=(MySingleton const& copy); // Not Implemented
public:
static MySingleton& getInstance()
{
// The only instance
// Guaranteed to be lazy initialized
// Guaranteed that it will be destroyed correctly
static MySingleton instance;
return instance;
}
};
D'ACCORD. Permet de rassembler quelques critiques et autres implémentations.
:-)
la source
Réponses:
Vous avez tous tort. Lisez la question. Répondre:
Utilisez un singleton si:
N'utilisez pas un Singleton si:
Comment créer le meilleur singleton:
la source
Les singletons vous donnent la possibilité de combiner deux mauvais traits dans une classe. C'est faux à peu près dans tous les sens.
Un singleton vous donne:
Le numéro un est simple. Les globaux sont généralement mauvais. Nous ne devons jamais rendre les objets accessibles au monde à moins d'en avoir vraiment besoin.
Le numéro deux peut sembler logique, mais réfléchissons-y. À quand remonte la dernière fois que vous avez ** accidentellement * créé un nouvel objet au lieu de référencer un existant? Comme il s'agit du tag C ++, utilisons un exemple de ce langage. Ecrivez-vous souvent accidentellement
Quand vous aviez l'intention d'écrire
Bien sûr que non. Nous n'avons pas besoin de protection contre cette erreur, car ce type d'erreur ne se produit tout simplement pas. Si c'est le cas, la bonne réponse est de rentrer à la maison et de dormir pendant 12 à 20 heures et j'espère que vous vous sentirez mieux.
Si un seul objet est nécessaire, créez simplement une instance. Si un objet doit être accessible globalement, faites-en un global. Mais cela ne signifie pas qu'il devrait être impossible d'en créer d'autres instances.
La contrainte «une seule instance est possible» ne nous protège pas vraiment contre les bogues probables. Mais il ne fait notre code très difficile à refactor et à entretenir. Parce que très souvent, nous découvrons plus tard que nous avions besoin de plus d'une instance. Nous n'avons plus d'une base de données, nous ne l' avons plus d'un objet de configuration, nous ne voulons plusieurs enregistreurs. Nos tests unitaires peuvent vouloir créer et recréer ces objets à chaque test, pour prendre un exemple courant.
Donc , un singleton doit être utilisé si et seulement si, nous avons besoin à la fois les caractéristiques qu'il offre: Si nous devons un accès mondial ( ce qui est rare, parce que globals sont généralement découragés) et nous avons besoin pour empêcher quiconque de jamais créer plus d'une instance d'un classe (ce qui me semble être un problème de conception). La seule raison pour laquelle je peux voir cela est si la création de deux instances corromprait l'état de notre application - probablement parce que la classe contient un certain nombre de membres statiques ou une bêtise similaire. Dans ce cas, la réponse évidente est de corriger cette classe. Cela ne devrait pas dépendre d'être la seule instance.
Si vous avez besoin d'un accès global à un objet, faites-en un global, comme
std::cout
. Mais ne limitez pas le nombre d'instances qui peuvent être créées.Si vous avez absolument besoin de limiter le nombre d'instances d'une classe à une seule, et qu'il n'y a aucun moyen de créer une deuxième instance en toute sécurité, appliquez-le. Mais ne le rendez pas également accessible à l'échelle mondiale.
Si vous avez besoin des deux traits, 1) faites-en un singleton et 2) faites-moi savoir pourquoi vous en avez besoin, car j'ai du mal à imaginer un tel cas.
la source
Le problème avec les singletons n'est pas leur mise en œuvre. C'est qu'ils confondent deux concepts différents, dont aucun n'est évidemment souhaitable.
1) Les singletons fournissent un mécanisme d'accès global à un objet. Bien qu'ils puissent être légèrement plus sûrs pour les threads ou légèrement plus fiables dans les langues sans ordre d'initialisation bien défini, cette utilisation est toujours l'équivalent moral d'une variable globale. C'est une variable globale habillée d'une syntaxe maladroite (foo :: get_instance () au lieu de g_foo, disons), mais elle sert exactement le même but (un seul objet accessible dans tout le programme) et a exactement les mêmes inconvénients.
2) Les singletons empêchent les instanciations multiples d'une classe. Il est rare, IME, que ce type de fonctionnalité soit intégré dans une classe. C'est normalement une chose beaucoup plus contextuelle; beaucoup de choses qui sont considérées comme une et une seule ne sont en réalité que des choses qui ne sont qu’une seule. OMI, une solution plus appropriée consiste à ne créer qu'une seule instance - jusqu'à ce que vous réalisiez que vous avez besoin de plusieurs instances.
la source
Une chose avec les modèles: ne généralisez pas . Ils ont tous les cas où ils sont utiles et quand ils échouent.
Singleton peut être désagréable lorsque vous devez tester le code. Vous êtes généralement coincé avec une instance de la classe et pouvez choisir entre ouvrir une porte dans le constructeur ou une méthode pour réinitialiser l'état, etc.
Un autre problème est que le Singleton n'est en fait rien de plus qu'une variable globale déguisée. Lorsque vous avez trop d'état partagé global sur votre programme, les choses ont tendance à revenir en arrière, nous le savons tous.
Cela peut rendre le suivi des dépendances plus difficile. Lorsque tout dépend de votre Singleton, il est plus difficile de le changer, de le diviser en deux, etc. Vous êtes généralement coincé avec. Cela entrave également la flexibilité. Enquêter sur un cadre d' injection de dépendance pour tenter de résoudre ce problème.
la source
Les singletons vous permettent essentiellement d'avoir un état global complexe dans des langues qui autrement rendent difficile ou impossible d'avoir des variables globales complexes.
Java en particulier utilise des singletons en remplacement des variables globales, car tout doit être contenu dans une classe. Les variables globales les plus proches sont les variables statiques publiques, qui peuvent être utilisées comme si elles étaient globales avec
import static
C ++ possède des variables globales, mais l'ordre dans lequel les constructeurs de variables de classe globales sont invoquées n'est pas défini. En tant que tel, un singleton vous permet de différer la création d'une variable globale jusqu'à la première utilisation de cette variable.
Les langages tels que Python et Ruby utilisent très peu de singletons car vous pouvez utiliser à la place des variables globales dans un module.
Alors, quand est-il bon / mauvais d'utiliser un singleton? À peu près exactement quand il serait bon / mauvais d'utiliser une variable globale.
la source
Modern C ++ Design by Alexandrescu a un singleton générique hérité du thread-safe.
Pour ma valeur 2p, je pense qu'il est important d'avoir des durées de vie définies pour vos singletons (quand il est absolument nécessaire de les utiliser). Je ne laisse normalement pas la
get()
fonction statique instancier quoi que ce soit, et laisse la configuration et la destruction à une section dédiée de l'application principale. Cela permet de mettre en évidence les dépendances entre singletons - mais, comme souligné ci-dessus, il est préférable de les éviter si possible.la source
Il y a un problème que je n'ai jamais vu mentionné, quelque chose que j'ai rencontré lors d'un emploi précédent. Nous avions des singletons C ++ qui étaient partagés entre les DLL, et les mécanismes habituels pour garantir qu'une seule instance d'une classe ne fonctionnent tout simplement pas. Le problème est que chaque DLL obtient son propre ensemble de variables statiques, ainsi que l'EXE. Si votre fonction get_instance est en ligne ou fait partie d'une bibliothèque statique, chaque DLL se terminera avec sa propre copie du "singleton".
La solution consiste à s'assurer que le code singleton n'est défini que dans une DLL ou EXE, ou à créer un gestionnaire singleton avec ces propriétés pour répartir les instances.
la source
Le premier exemple n'est pas sûr pour les threads - si deux threads appellent getInstance en même temps, cette statique va être un PITA. Une certaine forme de mutex aiderait.
la source
Comme d'autres l'ont noté, les principaux inconvénients des singletons incluent l'incapacité de les étendre et la perte du pouvoir d'instancier plus d'une instance, par exemple à des fins de test.
Quelques aspects utiles des singletons:
Cependant, vous n'avez pas besoin d'utiliser un singleton pour obtenir ces avantages. Vous pouvez écrire un objet normal qui fait le travail, puis demander à des personnes d'y accéder via une usine (un objet séparé). L'usine peut se soucier de n'en instancier qu'une seule, de la réutiliser, etc., si besoin est. De plus, si vous programmez sur une interface plutôt que sur une classe concrète, l'usine peut utiliser des stratégies, c'est-à-dire que vous pouvez activer et désactiver diverses implémentations de l'interface.
Enfin, une usine se prête à des technologies d'injection de dépendance comme Spring, etc.
la source
Les singletons sont pratiques lorsque vous avez beaucoup de code en cours d'exécution lorsque vous initialisez et objectez. Par exemple, lorsque vous utilisez iBatis lorsque vous configurez un objet de persistance, il doit lire toutes les configurations, analyser les cartes, s'assurer que tout est correct, etc. avant d'accéder à votre code.
Si vous faisiez cela à chaque fois, les performances seraient considérablement dégradées. En l'utilisant dans un singleton, vous prenez ce coup une fois et tous les appels suivants n'ont pas à le faire.
la source
La véritable chute des Singletons est qu'ils rompent l'héritage. Vous ne pouvez pas dériver une nouvelle classe pour vous offrir des fonctionnalités étendues à moins d'avoir accès au code où le Singleton est référencé. Ainsi, au-delà du fait que le Singleton rendra votre code étroitement couplé (réparable par un modèle de stratégie ... alias Dependency Injection), il vous empêchera également de fermer des sections du code de la révision (bibliothèques partagées).
Ainsi, même les exemples d'enregistreurs ou de pools de threads ne sont pas valides et doivent être remplacés par des stratégies.
la source
La plupart des gens utilisent des singletons lorsqu'ils essaient de se sentir à l'aise avec l'utilisation d'une variable globale. Il existe des utilisations légitimes, mais la plupart du temps lorsque les gens les utilisent, le fait qu'il ne peut y avoir qu'une seule instance n'est qu'un fait trivial par rapport au fait qu'il est accessible à l'échelle mondiale.
la source
Étant donné qu'un singleton ne permet de créer qu'une seule instance, il contrôle efficacement la réplication des instances. par exemple, vous n'auriez pas besoin de plusieurs instances d'une recherche - une carte de recherche morse par exemple, donc l'envelopper dans une classe singleton est approprié. Et ce n'est pas parce que vous avez une seule instance de la classe que vous êtes également limité sur le nombre de références à cette instance. Vous pouvez mettre les appels en file d'attente (pour éviter les problèmes de thread) sur l'instance et effectuer les modifications nécessaires. Oui, la forme générale d'un singleton est une forme publique mondiale, vous pouvez certainement modifier la conception pour créer un singleton à accès plus restreint. Je n'ai jamais fatigué cela auparavant mais je sais que c'est possible. Et pour tous ceux qui ont dit que le motif singleton est totalement diabolique, vous devez savoir ceci:
la source
Mais quand j'ai besoin de quelque chose comme un Singleton, je finis souvent par utiliser un compteur Schwarz pour l'instancier.
la source
Vous trouverez ci-dessous la meilleure approche pour implémenter un modèle singleton thread-safe avec désallocation de la mémoire dans le destructeur lui-même. Mais je pense que le destructeur devrait être facultatif car l'instance de singleton sera automatiquement détruite à la fin du programme:
Concernant les situations où nous devons utiliser des classes singleton peuvent être- Si nous voulons maintenir l'état de l'instance tout au long de l'exécution du programme Si nous sommes impliqués dans l'écriture dans le journal d'exécution d'une application où une seule instance du fichier doit être utilisé .... et ainsi de suite. Ce sera appréciable si quelqu'un peut suggérer une optimisation dans mon code ci-dessus.
la source
J'utilise des singletons comme test d'entrevue.
Lorsque je demande à un développeur de nommer certains modèles de conception, s'ils ne peuvent nommer que Singleton, ils ne sont pas embauchés.
la source
Anti-utilisation:
Un problème majeur avec une utilisation excessive de singleton est que le modèle empêche une extension et un échange faciles d'implémentations alternatives. Le nom de classe est codé en dur partout où le singleton est utilisé.
la source
Je pense que c'est la version la plus robuste pour C #:
Voici la version optimisée .NET :
Vous pouvez trouver ce modèle sur dotfactory.com .
la source
Le motif Meyers singleton fonctionne assez bien la plupart du temps, et dans les occasions où il le fait, il n'est pas nécessairement payant de chercher quelque chose de mieux. Tant que le constructeur ne lancera jamais et qu'il n'y a pas de dépendances entre singletons.
Un singleton est une implémentation pour un objet accessible globalement (GAO à partir de maintenant) bien que tous les GAO ne soient pas des singletons.
Les enregistreurs eux-mêmes ne devraient pas être des singletons, mais les moyens de journalisation devraient idéalement être accessibles à l'échelle mondiale, pour découpler où le message de journal est généré d'où et comment il est enregistré.
L'évaluation paresseux / paresseux est un concept différent et singleton l'implémente généralement aussi. Il vient avec beaucoup de ses propres problèmes, en particulier la sécurité des threads et les problèmes s'il échoue avec des exceptions telles que ce qui semblait être une bonne idée à l'époque ne s'avère pas si bon après tout. (Un peu comme la mise en œuvre de COW dans les chaînes).
Dans cet esprit, les GOA peuvent être initialisés comme suit:
Cela n'a pas besoin d'être fait aussi grossièrement que cela, et clairement dans une bibliothèque chargée qui contient des objets, vous voulez probablement un autre mécanisme pour gérer leur durée de vie. (Mettez-les dans un objet que vous obtenez lorsque vous chargez la bibliothèque).
Quant à quand j'utilise des singletons? Je les ai utilisés pour 2 choses - Une table singleton qui indique à quelles bibliothèques ont été chargées dlopen - Un gestionnaire de messages auquel les enregistreurs peuvent s'abonner et auquel vous pouvez envoyer des messages. Requis spécifiquement pour les gestionnaires de signaux.
la source
Je ne comprends toujours pas pourquoi un singleton doit être global.
J'allais produire un singleton où j'ai caché une base de données à l'intérieur de la classe en tant que variable statique constante privée et créer des fonctions de classe qui utilisent la base de données sans jamais exposer la base de données à l'utilisateur.
Je ne vois pas pourquoi cette fonctionnalité serait mauvaise.
la source
Je les trouve utiles lorsque j'ai une classe qui encapsule beaucoup de mémoire. Par exemple, dans un jeu récent sur lequel j'ai travaillé, j'ai une classe de carte d'influence qui contient une collection de très grands tableaux de mémoire contiguë. Je veux que tout soit alloué au démarrage, tout libéré à l'arrêt et je ne veux certainement qu'une seule copie de celui-ci. Je dois également y accéder depuis de nombreux endroits. Je trouve que le motif singleton est très utile dans ce cas.
Je suis sûr qu'il existe d'autres solutions mais je trouve celle-ci très utile et facile à mettre en œuvre.
la source
Si vous êtes celui qui a créé le singleton et qui l'utilise, ne le faites pas comme singleton (cela n'a pas de sens car vous pouvez contrôler la singularité de l'objet sans le rendre singleton) mais cela a du sens lorsque vous développez un et vous souhaitez fournir un seul objet à vos utilisateurs (dans ce cas, c'est vous qui avez créé le singleton, mais vous n'êtes pas l'utilisateur).
Les singletons sont des objets, alors utilisez-les comme objets, beaucoup de gens accèdent directement aux singletons en appelant la méthode qui le renvoie, mais cela est nuisible parce que vous faites savoir à votre code que l'objet est singleton, je préfère utiliser des singletons comme objets, je les passe à travers le constructeur et je les utilise comme des objets ordinaires, de cette façon, votre code ne sait pas si ces objets sont singletons ou non et cela rend les dépendances plus claires et cela aide un peu pour le refactoring ...
la source
Dans les applications de bureau (je sais, seuls nous, les dinosaures, nous les écrivons plus!), Ils sont essentiels pour obtenir des paramètres d'application globaux relativement immuables - la langue de l'utilisateur, le chemin d'accès aux fichiers d'aide, les préférences de l'utilisateur, etc. qui autrement devraient se propager dans chaque classe et chaque boîte de dialogue .
Modifier - bien sûr, ceux-ci doivent être en lecture seule!
la source
Une autre implémentation
la source
Instance()
renvoyer un pointeur, pas une référence. A l' intérieur de votre.cpp
fichier, initialiser l'instance null:Singleton* Singleton::instance_ = nullptr;
. EtInstance()
devrait être mis en œuvre:if (instance_ == nullptr) instance_ = new Singleton(); return instance_;
.