web-dev-qa-db-fra.com

Quel est le problème avec singletons?

singleton pattern est un membre entièrement payé de GoF 's carnet de patrons , mais il semble que ces derniers soient plutôt orphelins du monde des développeurs. J'utilise toujours beaucoup de singletons, en particulier pour classes d'usine , et bien que vous deviez faire attention aux problèmes de multithreading (comme n'importe quelle classe en fait), je ne vois pas pourquoi ils sont si terribles.

Stack Overflow semble en particulier supposer que tout le monde convient que les singletons sont diaboliques. Pourquoi?

Veuillez étayer vos réponses par " faits, références ou expertises spécifiques "

1903
Ewan Makepeace

Paraphrasé de Brian Button:

  1. Ils sont généralement utilisés comme une instance globale, pourquoi est-ce si grave? Parce que vous masquez les dépendances de votre application dans votre code, au lieu de les exposer via les interfaces. Faire quelque chose de global pour éviter de le faire circuler est un odeur de code .

  2. Ils violent le principe de responsabilité unique : en raison du fait qu'ils contrôlent leur propre création et leur cycle de vie.

  3. Ils font intrinsèquement que le code soit étroitement couplé . Cela rend leur simulation assez difficile dans de nombreux cas.

  4. Ils portent l'état pendant la durée de vie de l'application. Les tests sont un autre succès, car vous pouvez vous retrouver dans une situation où il faut commander des tests, ce qui est un gros non pour les tests unitaires. Pourquoi? Parce que chaque test unitaire doit être indépendant de l'autre.

1246
Jim Burger

Les singletons résolvent un (et un seul) problème.

Conflit de ressources.

Si vous avez une ressource qui

( 1 ) ne peut avoir qu'une seule instance, et

( 2 ) vous devez gérer cette instance unique,

vous avez besoin d'un singleton .

Il n'y a pas beaucoup d'exemples. Un fichier de log est le gros. Vous ne voulez pas simplement abandonner un seul fichier journal. Vous voulez vider, synchroniser et fermer correctement. Voici un exemple de ressource partagée unique devant être gérée.

Il est rare que vous ayez besoin d'un singleton. La raison pour laquelle ils sont mauvais est qu’ils se sentent comme un global et qu’ils sont un membre entièrement libéré du GoF Design Patterns livre.

Lorsque vous pensez avoir besoin d'un global, vous faites probablement une terrible erreur de conception.

434
S.Lott

Certains snobs codeurs les considèrent comme un global glorifié. De la même manière que beaucoup de gens détestent la déclaration goto, il en existe d'autres qui détestent l'idée de jamais utiliser un global. J'ai vu plusieurs développeurs faire des efforts extraordinaires pour éviter un global car ils considéraient en utiliser un comme un aveu d'échec. Etrange mais vrai.

En pratique, le modèle Singleton est simplement une technique de programmation utile dans votre boîte à outils. De temps en temps, vous pourriez trouver la solution idéale et vous en servir. Mais l’utiliser simplement pour pouvoir vous vanter d’utiliser un motif est aussi stupide que de ne jamais l’utiliser, car c’est juste un global.

334
Phil Wright

Misko Hevery, de Google, a publié des articles intéressants sur ce sujet ...

Les singletons sont des menteurs pathologiques présente un exemple de test unitaire qui montre comment les singletons peuvent rendre difficile l'identification des chaînes de dépendance et le démarrage ou le test d'une application. C'est un exemple assez extrême d'abus, mais l'argument qu'il avance est toujours valable:

Les singletons ne sont rien de plus qu'un état global. L'état global permet à vos objets de récupérer secrètement des éléments non déclarés dans leurs API et, par conséquent, les singletons transforment vos API en menteurs pathologiques.

Où se trouvent tous les singletons partis indique que l'injection de dépendance a facilité l'accès des constructeurs aux instances qui en ont besoin, ce qui atténue le besoin sous-jacent des mauvais singletons globaux décriés dans le premier article.

212
jason

Je pense que la confusion est causée par le fait que les gens ne connaissent pas la véritable application du modèle Singleton. Je ne saurais trop insister là-dessus. Singleton est not un motif pour envelopper les globaux. Le modèle Singleton ne doit être utilisé que pour garantir que ne et une seule instance d'une classe donnée existe pendant l'exécution.

Les gens pensent que Singleton est diabolique parce qu’ils l’utilisent pour des globals. C'est à cause de cette confusion que Singleton est méprisé. S'il vous plaît, ne confondez pas Singletons et globals. Si utilisé aux fins pour lesquelles il était destiné, vous obtiendrez des avantages extrêmes du modèle Singleton.

114
Cem Catikkas

Une des mauvaises choses à propos des singletons est que vous ne pouvez pas les étendre très facilement. Vous devez fondamentalement intégrer une sorte de motif décoratif ou quelque chose du genre si vous voulez changer leur comportement. En outre, si un jour vous voulez avoir plusieurs façons de faire cela, il peut être assez pénible de changer, en fonction de la manière dont vous présentez votre code.

Une chose à noter, si vous utilisez des singletons, essayez de les transmettre à ceux qui en ont besoin plutôt que de les laisser y accéder directement ... Sinon, si vous choisissez d’avoir plusieurs façons de faire ce que singleton fait, ce sera plutôt difficile à changer car chaque classe incorpore une dépendance si elle accède directement au singleton.

Donc en gros:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

plutôt que:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Je crois que ce type de modèle s'appelle injection de dépendance et est généralement considéré comme une bonne chose.

Comme dans tout modèle ... Pensez-y et déterminez si son utilisation dans la situation donnée est inappropriée ou non ... Les règles sont conçues pour être enfreintes de manière générale, et modèles ne devraient pas être appliquées bon gré mal gré pensée.

72
Mike Stone

Le motif singleton n'est pas un problème en soi. Le problème est que le motif est souvent utilisé par les personnes développant des logiciels avec des outils orientés objet, sans avoir une compréhension solide des concepts de OO. Lorsque des singletons sont introduits dans ce contexte, ils tendent à devenir des classes ingérables qui contiennent des méthodes d'assistance pour chaque petite utilisation.

Les singletons sont également un problème du point de vue des tests. Ils ont tendance à rendre les tests unitaires isolés difficiles à écrire. Inversion du contrôle (IoC) et injection de dépendance sont des modèles destinés à résoudre ce problème d’une manière orientée objet qui se prête aux tests unitaires.

Dans un environnement ordures collectées , les singletons peuvent rapidement devenir un problème en ce qui concerne la gestion de la mémoire.

Il existe également le scénario multithread dans lequel les singletons peuvent devenir un goulot d'étranglement ainsi qu'un problème de synchronisation.

68
Kimoz

Un singleton est mis en œuvre en utilisant une méthode statique. Les personnes qui font des tests unitaires évitent les méthodes statiques car elles ne peuvent être ni moquées ni écrasées. La plupart des gens sur ce site sont de grands partisans des tests unitaires. La convention généralement acceptée pour les éviter utilise le modèle inversion du contrôle .

53
jwanagel

Les singletons sont aussi mauvais quand il s'agit de clustering. Parce qu'alors, vous n'avez plus "exactement un singleton" dans votre application.

Considérez la situation suivante: En tant que développeur, vous devez créer une application Web qui accède à une base de données. Pour vous assurer que les appels de base de données simultanés ne se contredisent pas, vous créez un thread-save SingletonDao:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

Vous êtes donc sûr qu’un seul singleton existe dans votre application et que toutes les bases de données passent par ce seul et unique SingletonDao. Votre environnement de production ressemble maintenant à ceci: Single Singleton

Tout va bien jusqu'à présent.

Maintenant, considérez que vous souhaitez configurer plusieurs instances de votre application Web dans un cluster. Maintenant, vous avez soudainement quelque chose comme ça:

Many singletons

Cela semble étrange, mais maintenant vous avez plusieurs singletons dans votre application. Et c’est exactement ce qu’un singleton n’est pas censé être: avoir beaucoup d’objets. Ceci est particulièrement grave si, comme le montre cet exemple, vous souhaitez effectuer des appels synchronisés vers une base de données.

Bien entendu, il s’agit d’un exemple de mauvaise utilisation d’un singleton. Mais le message de cet exemple est le suivant: vous ne pouvez pas compter sur le fait qu’il existe exactement une instance d’un singleton dans votre application, en particulier en ce qui concerne le clustering.

43
Uooo
  1. Il est facilement (ab) utilisé comme variable globale.
  2. Les classes qui dépendent de singletons sont relativement plus difficiles à tester unitaire isolément.
38
jop

Le monopole est le diable et les singletons dont l'état n'est pas en lecture seule/mutable sont le problème "réel" ...

Après avoir lu les singletons sont des menteurs pathologiques comme suggéré dans réponse de jason je suis tombé sur cette petite friandise qui fournit le meilleur exemple présenté de comment les singletons sont souvent mal utilisés.

Global est mauvais parce que:

  • une. Cela provoque un conflit d'espace de noms
  • b. Il expose l'État d'une manière injustifiée

Quand il s'agit de singletons

  • une. La manière explicite OO de les appeler évite les conflits, alors pointez a. n'est pas un problème
  • b. Les singletons sans état sont (comme les usines) ne sont pas un problème. Les singletons avec state peuvent à nouveau appartenir à deux catégories, celles qui sont immuables ou qui écrivent une fois et lisent beaucoup (fichiers de configuration/propriété). Ce ne sont pas mauvais. Singletons Mutable, qui sont des types de détenteurs de référence sont ceux dont vous parlez.

Dans la dernière déclaration, il fait référence au concept du blog "les singletons sont des menteurs".

Comment cela s’applique-t-il au monopole?

Pour commencer un jeu de monopole, d'abord:

  • nous établissons les règles en premier afin que tout le monde soit sur la même page
  • tout le monde a le même départ au début du jeu
  • un seul ensemble de règles est présenté pour éviter toute confusion
  • les règles ne sont pas autorisées à changer tout au long du jeu

Maintenant, pour ceux qui n'ont pas vraiment joué le monopole, ces normes sont au mieux idéales. Une défaite en monopole est difficile à avaler, car le monopole est une question d'argent. Si vous perdez, vous devez regarder minutieusement le reste des joueurs terminer le match. Les pertes sont généralement Swift et écrasantes. Ainsi, les règles sont généralement tordues à un moment donné pour servir les intérêts personnels de certains joueurs au détriment des autres.

Donc, vous jouez le monopole avec vos amis Bob, Joe et Ed. Vous construisez rapidement votre empire et consommez une part du marché à un taux exponentiel. Vos adversaires faiblissent et vous commencez à sentir le sang (au sens figuré). Votre copain, Bob, a investi tout son argent dans le plus grand nombre possible d’immeubles de faible valeur, mais il ne reçoit pas un retour sur investissement aussi élevé que prévu. Par malchance, Bob atterrit sur votre promenade et est excisé du match.

Maintenant, le jeu passe du jeu de dés amical aux affaires sérieuses. Bob a été cité en exemple d'échec et Joe et Ed ne veulent pas se retrouver comme "ce mec". Donc, en tant que joueur principal, vous devenez tout à coup l'ennemi. Joe et Ed commencent à s’exercer à des métiers clandestins, à des injections d’argent dans le dos, à des échanges de maison sous-évalués et généralement à tout ce qui peut vous affaiblir en tant que joueur jusqu’à ce que l’un d’entre eux atteigne le sommet.

Ensuite, au lieu que l’un d’eux gagne, le processus recommence à zéro. Tout à coup, un ensemble limité de règles devient une cible mouvante et le jeu dégénère en un type d'interactions sociales qui constituerait le fondement de chaque émission de télé-réalité de premier plan depuis Survivor. Pourquoi, parce que les règles changent et qu'il n'y a pas de consensus sur comment/pourquoi/ce qu'elles sont censées représenter, et plus important encore, il n'y a pas une seule personne qui prend les décisions. Chaque joueur dans le jeu, à ce stade, établit ses propres règles et le chaos s'ensuit jusqu'à ce que deux des joueurs soient trop fatigués pour continuer la charade et abandonner lentement.

Ainsi, si un livre de règles pour un jeu représente avec précision un singleton, le livre de règles de monopole serait un exemple d’abus.

Comment cela s'applique-t-il à la programmation?

En plus de tous les problèmes évidents de sécurité des threads et de synchronisation que les singletons modifiables présentent ... Si vous disposez d'un ensemble de données, celui-ci peut être lu/manipulé par plusieurs sources différentes simultanément et existe pendant la durée de l'exécution de l'application, c'est probablement un bon moment pour prendre du recul et demander "utilise-t-je le bon type de structure de données ici".

Personnellement, j'ai vu un programmeur abuser d'un singleton en l'utilisant comme une sorte de magasin de base de données croisé tordu au sein d'une application. Ayant travaillé sur le code directement, je peux attester qu'il était lent (à cause de tous les verrous de threads nécessaires pour le rendre thread-safe) et un cauchemar à travailler (à cause de la nature imprévisible/intermittente des bugs de synchronisation), et presque impossible à tester dans des conditions de "production". Bien sûr, un système aurait pu être développé en utilisant la polling/signalisation pour résoudre certains problèmes de performances, mais cela ne résoudrait pas les problèmes de tests et pourquoi s'inquiéter lorsqu'une "vraie" base de données peut déjà accomplir les mêmes fonctionnalités dans un environnement beaucoup plus robuste/de manière évolutive.

Un singleton est seulement une option si vous avez besoin de ce qu'un singleton fournit. Une instance en lecture seule d'un objet. Cette même règle devrait également se répercuter sur les propriétés/membres de l'objet.

31
Evan Plaice

Singleton ne concerne pas une instance unique!

Contrairement à d'autres réponses, je ne veux pas parler de ce qui ne va pas avec Singletons, mais vous montrer à quel point ils sont puissants et impressionnants lorsqu'ils sont utilisés correctement!

  • Problème : Singleton peut être un défi dans un environnement multi-threading
    Solution : utilisez un seul processus threadé bootstrap pour initialiser toutes les dépendances de votre singleton.
  • Problème : Il est difficile de se moquer des singletons.
    Solution : Utilisez la méthode sine motif pour vous moquer

Vous pouvez mapper MyModel à TestMyModel classe qui en hérite, partout où MyModel sera injecté, vous obtiendrez TestMyModel instread. - Problème : Les singletons peuvent provoquer des fuites de mémoire car ils ne sont jamais éliminés.
Solution : Bien, disposez-les! Pour implémenter un rappel dans votre application afin de disposer correctement des singletons, vous devez supprimer toutes les données qui leur sont liées et enfin: les supprimer de la fabrique.

Comme je l'ai dit au titre, singleton ne concerne pas une instance unique.

  • Singletons améliore la lisibilité : Vous pouvez regarder votre classe et voir quel singleton elle a injecté pour déterminer quelles sont ses dépendances.
  • Singletons améliore la maintenance : une fois que vous avez supprimé une dépendance d'une classe, vous venez de supprimer une injection singleton, vous n'avez pas besoin de modifier un gros lien de autres classes qui viennent de déplacer votre dépendance (c'est du code nauséabond pour moi @ Jim Burger )
  • Singletons améliore la mémoire et les performances : lorsque quelque chose se produit dans votre application et que cela prend une longue chaîne de rappels, vous gaspillez de la mémoire et des performances, en utilisant Singleton, vous coupez les intermédiaires et améliorez vos performances et votre utilisation de la mémoire (en évitant les affectations inutiles de variables locales).
23
Ilya Gazman

Ma réponse sur la façon dont les singletons sont mauvais est toujours, "ils sont difficiles à faire correctement". La plupart des composants fondamentaux des langages sont des singletons (classes, fonctions, espaces de noms et même opérateurs), de même que des composants d'autres aspects de l'informatique (localhost, route par défaut, système de fichiers virtuel, etc.), et ce n'est pas par hasard. S'ils causent parfois des ennuis et des frustrations, ils peuvent également faire beaucoup mieux le travail.

Les deux problèmes les plus importants que je vois sont: le traiter comme un global et ne pas définir la fermeture de Singleton.

Tout le monde parle de Singleton en tant que globals, parce qu'ils sont fondamentalement. Cependant, beaucoup (malheureusement pas tous) de la méchanceté dans un global ne provient pas intrinsèquement de la globalisation, mais de la façon dont vous l'utilisez. Il en va de même pour les singletons. En réalité, d'autant plus que "instance unique" n'a pas besoin de signifier "accessible globalement". C'est plutôt un sous-produit naturel, et compte tenu de tout le mal dont nous sommes conscients, nous ne devrions pas être aussi pressés d'exploiter l'accessibilité mondiale. Une fois que les programmeurs voient un Singleton, ils semblent toujours y accéder directement via sa méthode d'instance. Au lieu de cela, vous devriez y accéder comme n'importe quel autre objet. La plupart des codes ne devraient même pas savoir qu'il s'agit d'un Singleton (couplage lâche, n'est-ce pas?). Si seulement un petit morceau de code accède à l'objet comme s'il s'agissait d'un global, beaucoup de dommages sont annulés. Je recommande de l'appliquer en limitant l'accès à la fonction d'instance.

Le contexte de Singleton est également très important. La caractéristique déterminante d'un Singleton est qu'il n'y a "qu'un seul", mais la vérité est qu'il s'agit "d'un seul" dans une sorte de contexte/espace de nom. Ils sont généralement l’un des suivants: un par thread, processus, adresse IP ou cluster, mais peuvent également être un par processeur, ordinateur, espace de noms de langage/chargeur de classe/peu importe, sous-réseau, Internet, etc.

L’autre erreur, moins fréquente, consiste à ignorer le mode de vie Singleton. Ce n’est pas parce qu’il n’en existe qu’un seul qui signifie qu'un Singleton est omnipotent, "il a toujours été et sera toujours", et il n’est généralement pas souhaitable (les objets sans début ni fin violent toutes les hypothèses utiles dans le code et ne doivent être utilisés que par lui. dans le plus désespéré des circonstances.

Si vous évitez ces erreurs, Singletons peut toujours être un PITA, mais il est prêt à résoudre un grand nombre des problèmes les plus graves. Imaginez un singleton Java, défini explicitement comme étant une fois par chargeur de classe (ce qui signifie qu'il a besoin d'une politique de sécurité des threads), avec des méthodes de création et de destruction définies et un cycle de vie dictant quand et comment ils sont invoqués, et dont la méthode "instance" dispose d'une protection de package, l'accès à celui-ci se fait généralement via d'autres objets non globaux. Toujours une source potentielle de problèmes, mais certainement beaucoup moins de problèmes.

Malheureusement, plutôt que d'enseigner de bons exemples sur la manière de faire des singletons. Nous enseignons de mauvais exemples, nous laissons les programmeurs les utiliser pendant un moment, puis nous leur disons qu’ils constituent un mauvais modèle.

22

Voir Wikipedia Singleton_pattern

Il est également considéré comme un anti-modèle par certaines personnes, qui estiment qu'il est trop utilisé, introduisant des limitations inutiles dans les situations où un seul cas de classe n'est pas réellement requis. [1] [2] [3] [4]

Références (uniquement les références pertinentes de l'article)

  1. ^ Alex Miller. Patterns I hate # 1: Singleton , juillet 2007
  2. ^ Scott Densmore. Pourquoi les singletons sont diaboliques , mai 2004
  3. ^ Steve Yegge. Singletons considérés comme stupides , septembre 2004
  4. ^ J.B. Rainsberger, IBM. tilisez vos singletons à bon escient , juillet 2001
21
GUI Junkie

Ce n'est pas que les singletons soient mauvais en soi, mais le modèle de conception GoF. Le seul argument réellement valable est que le modèle de conception GoF ne se prête pas au test, en particulier si les tests sont exécutés en parallèle.

L'utilisation d'une instance unique d'une classe est une construction valide tant que vous appliquez les moyens suivants dans le code:

  1. Assurez-vous que la classe qui sera utilisée en tant que singleton implémente une interface. Ceci permet aux stubs ou aux mock d'être implémentés en utilisant la même interface

  2. Assurez-vous que le Singleton est thread-safe. C'est une donnée.

  3. Le singleton devrait être simple dans la nature et pas trop compliqué.

  4. Lors de l'exécution de votre application, où des singletons doivent être passés à un objet donné, utilisez une fabrique de classes qui construit cet objet et demandez à la fabrique de classes de transmettre l'instance singleton à la classe qui en a besoin.

  5. Pendant les tests et pour assurer un comportement déterministe, créez la classe singleton en tant qu'instance distincte, en tant que classe réelle ou en tant que stub/mock qui implémente son comportement et transmettez-le tel quel à la classe qui en a besoin. N'utilisez pas le facteur de classe qui crée l'objet soumis au test qui a besoin du singleton pendant le test, car il passera l'instance globale unique de celui-ci, ce qui annule l'objectif.

Nous avons utilisé Singletons dans nos solutions avec beaucoup de succès, ce qui permet de vérifier le comportement déterministe dans les flux de tests en parallèle.

17
user1578119

J'aimerais aborder les 4 points de la réponse acceptée, j'espère que quelqu'un pourra expliquer pourquoi je me trompe.

  1. Pourquoi cacher des dépendances dans votre code est-il mauvais? Il existe déjà des dizaines de dépendances cachées (appels au runtime C, appels à l'API du système d'exploitation, appels de fonctions globales), et les dépendances singleton sont faciles à trouver (search for instance ()).

    "Créer quelque chose de global pour éviter de le transmettre est une odeur de code." Pourquoi ne pas transmettre quelque chose pour éviter d'en faire un singleton une odeur de code?

    Si vous passez un objet à travers 10 fonctions dans une pile d'appels juste pour éviter un singleton, est-ce si formidable?

  2. Principe de responsabilité unique: Je pense que cela est un peu vague et dépend de votre définition de la responsabilité. Une question pertinente serait: pourquoi l’ajout de cette spécifique "responsabilité" à une classe est-il important?

  3. Pourquoi le fait de passer un objet à une classe le rend-il plus étroitement couplé que d'utiliser cet objet comme singleton à partir de la classe?

  4. Pourquoi cela change-t-il combien de temps l'état dure? Les singletons peuvent être créés ou détruits manuellement, de sorte que le contrôle est toujours là et que vous pouvez rendre la durée de vie identique à celle d'un objet non-singleton.

En ce qui concerne les tests unitaires:

  • toutes les classes n'ont pas besoin d'être testées à l'unité
  • toutes les classes nécessitant des tests unitaires n'ont pas besoin de changer l'implémentation du singleton
  • si elles do doivent être testées à l'unité et ont besoin de changer d'implémentation, il est facile de changer une classe en utilisant un singleton plutôt que de lui faire passer le singleton par injection de dépendance.
16
Jon

Vince Huston a ces critères, qui me semblent raisonnables:

Singleton ne devrait être envisagé que si les trois critères suivants sont remplis:

  • La propriété de l'instance unique ne peut pas être raisonnablement attribuée
  • Une initialisation lente est souhaitable
  • L'accès global n'est pas prévu ailleurs

Si la propriété de l'instance unique, quand et comment l'initialisation a lieu et si l'accès global n'est pas un problème, Singleton n'est pas suffisamment intéressant.

15
js.

Les singletons sont mauvais d'un point de vue puriste.

D'un point de vue pratique, un singleton est un compromis entre temps de développement et complexité .

Si vous savez que votre application ne changera pas tant que ça, ils sont assez acceptables. Sachez simplement que vous aurez peut-être besoin de reformuler votre travail si vos exigences changent de manière inattendue (ce qui est plutôt OK dans la plupart des cas).

Les singletons compliquent parfois aussi tests unitaires .

14
tacone

Il n’existe aucun problème inhérent au motif, à supposer qu’il soit utilisé pour certains aspects de votre modèle qui sont véritablement uniques.

Je crois que le contrecoup est dû à sa surutilisation, ce qui, à son tour, est dû au fait que c'est le modèle le plus facile à comprendre et à mettre en œuvre.

13
Ben Hoffstein

Je ne vais pas commenter l'argument bon/mauvais, mais je ne les ai pas utilisés depuis le Spring est arrivé. Utiliser injection de dépendance a quasiment supprimé mes exigences en termes de singleton, de réparateurs et d’usines. Je trouve que cet environnement est beaucoup plus productif et propre, du moins pour le type de travail que je fais (applications Web basées sur Java).

13
prule

Singleton est un modèle et peut être utilisé ou maltraité comme n'importe quel autre outil.

La mauvaise partie d'un singleton est généralement l'utilisateur (ou devrais-je dire l'utilisation inappropriée d'un singleton pour des choses pour lesquelles il n'est pas conçu). Le plus grand délinquant utilise un singleton comme fausse variable globale.

11
Martin York

Lorsque vous écrivez du code en utilisant des singletons, par exemple un enregistreur ou une connexion à une base de données, et que vous découvrez ensuite que vous avez besoin de plusieurs journaux ou de plusieurs bases de données, vous êtes en difficulté.

Les singletons rendent très difficile le déplacement des objets ordinaires.

En outre, il est trop facile d’écrire un singleton non thread-safe.

Plutôt que d'utiliser des singletons, vous devez passer tous les objets utilitaires nécessaires d'une fonction à l'autre. Cela peut être simplifié si vous les enroulez dans un objet assistant, comme ceci:

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}
8
Roman Odaisky

Article récent sur ce sujet par Chris Reath at Coding Without Comments .

Remarque: Le codage sans commentaires n'est plus valide. Cependant, l'article associé à a été cloné par un autre utilisateur.

http://geekswithblogs.net/AngelEyes/archive/2013/09/08/singleton-i-love-you-but-youre-bringing-me-down-re-uploaded.aspx

7
David

Les problèmes avec les singletons est la question de la portée accrue et donc couplage . Il est indéniable que dans certaines situations, vous devez avoir accès à une instance unique et vous pouvez le faire de différentes manières.

Je préfère maintenant concevoir autour d'un conteneur inversion de contrôle (IoC) et permettre aux durées de vie d'être contrôlées par le conteneur. Cela vous donne l'avantage des classes qui dépendent de l'instance pour ignorer le fait qu'il existe une seule instance. La durée de vie du singleton peut être modifiée à l'avenir. Un exemple que j'ai rencontré récemment était un ajustement facile d'un seul thread à un multi-thread.

FWIW, s’il s’agit d’une PIA lorsque vous essayez de le tester à l’unité, il passe à PIA lorsque vous essayez de le déboguer, de le corriger ou de l’améliorer.

7
Mark Lindell

Les singletons ne sont pas mauvais. Ce n’est que mauvais que de créer quelque chose d’unique au monde qui ne soit pas unique au monde.

Cependant, il existe des "services de portée d'application" (pensez à un système de messagerie qui fait interagir les composants) - cet APPEL pour un singleton, une classe "MessageQueue" - qui a une méthode "SendMessage (...)".

Vous pouvez alors faire ce qui suit de partout:

MessageQueue.Current.SendMessage (new MailArrivedMessage (...));

Et bien sûr faire:

MessageQueue.Current.RegisterReceiver (this);

dans les classes qui implémentent IMessageReceiver.

7

Voici encore une chose à propos des singletons que personne n’a encore dite.

Dans la plupart des cas, la "singletonity" est un détail d'implémentation pour une classe plutôt qu'une caractéristique de son interface. L'inversion de Control Container peut masquer cette caractéristique aux utilisateurs de la classe; il vous suffit de marquer votre classe en tant que singleton (avec l'annotation @Singleton dans Java par exemple) et c'est tout; IoCC fera le reste. Vous n'avez pas besoin de fournir un accès global à votre instance singleton, car l'accès est déjà géré par IoCC. Ainsi, il n'y a rien de mal avec IoC Singletons.

GoF Singletons contrairement à IoC Singletons sont supposés exposer la "singletonity" dans l'interface via la méthode getInstance (), et ainsi souffrir de tout ce qui est dit ci-dessus.

6
Volodymyr Frolov

Trop de gens mettent des objets qui ne sont pas thread-safe dans un motif singleton. J'ai vu des exemples d'un DataContext ( LINQ to SQL ) réalisé dans un modèle singleton, malgré le fait que le DataContext n'est pas thread-safe et est purement un objet d'unité de travail.

6
Aaron Powell

Singletons ne sont pas mal, si vous l'utilisez correctement & au minimum. Il existe de nombreux autres modèles de conception qui remplacent les besoins de singleton à un moment donné (et donnent également de meilleurs résultats). Mais certains programmeurs ne sont pas conscients de ces bons modèles et utilisent le singleton pour tous les cas, ce qui rend le singleton mal pour eux.

5
Sriram

Comme il s’agit essentiellement de variables globales orientées objet, vous pouvez généralement concevoir vos classes de manière à ne pas en avoir besoin.

4
Ycros

Une tendance se dégage lorsque plusieurs personnes (ou équipes) parviennent à des solutions similaires ou identiques. Beaucoup de gens utilisent encore des singletons dans leur forme originale ou en utilisant des modèles d'usine (bonne discussion dans Modern C++ Design d'Alexandrescu). La concurrence et la difficulté à gérer la durée de vie de l'objet sont les principaux obstacles, le premier pouvant être facilement géré comme vous le suggérez.

Comme tous les choix, Singleton a son lot de hauts et de bas. Je pense qu'ils peuvent être utilisés avec modération, en particulier pour les objets qui survivent à la durée de vie de l'application. Le fait qu’ils ressemblent (et le sont probablement) à des globaux a probablement déclenché les puristes.

4
user22044

Premièrement, une classe et ses collaborateurs doivent d'abord accomplir le but recherché plutôt que de se concentrer sur les déoendents. La gestion du cycle de vie (lorsque des instances sont créées et lorsqu'elles sortent du cadre) ne devrait pas faire partie de la responsabilité des cladses. La meilleure pratique acceptée consiste à concevoir ou à configurer un nouveau composant pour gérer les dépendances à l'aide de l'injection de dépendances.

Les logiciels deviennent souvent plus compliqués, il est donc logique d’avoir plusieurs instances indépendantes de la classe Singleton avec différents états. Commettre du code pour simplement saisir le singleton est une erreur dans de tels cas. L'utilisation de Singleton.getInstance() peut convenir à de petits systèmes simples, mais cela ne fonctionne pas et ne permet pas une mise à l'échelle lorsqu'il est nécessaire d'avoir une instance différente de la même classe.

Aucune classe ne devrait être considérée comme un singleton, mais plutôt comme une application de son utilisation ou de la manière dont elle est utilisée pour configurer les personnes à charge. Cela n’a pas d’importance pour les opérations rapides et désagréables - il suffit de lire les codes durs pour dire que les chemins de fichiers n’a pas d’importance, mais pour les applications plus grandes, de telles dépendances doivent être décomposées et gérées de manière plus appropriée à l’aide de DI.

Les problèmes que singleton pose lors des tests sont un symptôme de leur cas/environnement d'utilisation codé en dur. La suite de tests et les nombreux tests sont chacun un élément distinct qui n’est pas compatible avec le codage en dur d’un singleton.

4
mP.

Le Singleton - l'anti-pattern! de Mark Radford (Overload Journal n ° 57 - octobre 2003) est une bonne lecture de la raison pour laquelle Singleton est considéré comme un anti-modèle. L'article traite également de deux approches de conception alternatives pour remplacer Singleton.

3
Frank Grimm

C’est ce qui manque aux réponses jusqu’à présent:

Si vous avez besoin d'une instance de cet objet par espace adresse de processus (et que vous êtes aussi confiant que cette exigence ne changera pas), vous devez en faire un singleton.

Sinon, ce n'est pas un singleton.

C’est une exigence très étrange, qui n’intéresse guère l’utilisateur. Les processus et l'isolation de l'espace d'adressage sont un détail d'implémentation. Ils ont un impact uniquement sur l'utilisateur lorsqu'ils souhaitent arrêter votre application à l'aide de kill ou du gestionnaire de tâches.

Hormis la construction d'un système de mise en cache, il n'y a pas beaucoup de raisons pour lesquelles vous êtes si certain qu'il ne devrait y avoir qu'une seule instance par processus. Que diriez-vous d'un système de journalisation? Peut-être serait-il préférable que ce soit par thread ou plus finement afin que vous puissiez tracer l'origine des messages plus automatiquement. Que diriez-vous de la fenêtre principale de l'application? Ça dépend; peut-être voudrez-vous que tous les documents de l'utilisateur soient gérés par le même processus pour une raison quelconque, auquel cas il y aurait plusieurs "fenêtres principales" dans ce processus.

3
Daniel Earwicker

Quelques contrepoints de l'auteur:

Vous êtes bloqué si vous devez rendre la classe non unique à l'avenir Pas du tout - j'étais dans cette situation avec un seul singleton de connexion à la base de données que je voulais transformer en pool de connexion. Rappelez-vous que chaque singleton est accessible via une méthode standard:

MyClass.instance

Ceci est similaire à la signature d'une méthode factory. J'ai seulement mis à jour la méthode d'instance pour renvoyer la connexion suivante du pool - aucune autre modification requise. Cela aurait été beaucoup plus difficile si nous n'avions PAS utilisé de singleton.

Les singletons ne sont que des globales fantaisistes Je ne peux pas discuter, mais tous les champs et méthodes statiques le sont également - tout ce qui est accédé à partir de la classe plutôt que d'une instance est essentiellement global et je ne vois pas autant de recul sur utilisation de champs statiques?

Ne dites pas que les célibataires sont bons, mais repoussez une partie de la "sagesse conventionnelle".

3
Ewan Makepeace

Cela brouille le séparation des préoccupations .

En supposant que vous ayez un singleton, vous pouvez appeler cette instance de n’importe où dans votre classe. Votre classe n'est plus aussi pure qu'elle devrait l'être. Votre classe ne fonctionnera plus désormais sur ses membres et les membres qu’elle reçoit explicitement. Cela créera de la confusion, car les utilisateurs de la classe ne savent pas quelles sont les informations suffisantes dont la classe a besoin. L'idée même de encapsulation est de cacher le comment d'une méthode aux utilisateurs, mais si un singleton est utilisé à l'intérieur de la méthode, il faudra connaître l'état du singleton pour pouvoir utiliser la méthode. correctement. C'est anti - OOP .

2
Graviton

Du haut de ma tête:

  1. Ils imposent un couplage étroit. Si votre singleton réside sur un assembly différent de celui de son utilisateur, l'assembly using ne peut jamais fonctionner sans l'assembly contenant le singleton.
  2. Ils permettent des dépendances circulaires, par exemple, l’Assemblée A peut avoir un singleton avec une dépendance sur l’Assemblée B, et l’Assemblée B peut utiliser le singleton de l’Assemblée A. Tout cela sans casser le compilateur.
1
Jon Limjap