Qu'est-ce qui est si mauvais avec les singletons? [fermé]

1984

Le motif de singleton est membre entièrement libérées de la GoF d » motifs livre , mais il semble ces derniers temps plutôt rendus orphelins par le monde des développeurs. J'utilise encore pas mal de singletons, en particulier pour les classes d'usine , et bien que vous deviez faire un peu attention aux problèmes de multithreading (comme n'importe quelle classe en fait), je ne vois pas pourquoi ils sont si horribles.

Stack Overflow semble surtout supposer que tout le monde convient que les singletons sont mauvais. Pourquoi?

Veuillez étayer vos réponses par des « faits, références ou expertise spécifique »

m87
la source
6
Je dois dire que l'utilisation d'un design singleton m'a brûlé récemment car j'ai essayé d'adapter le code. Comme je le fais pendant mon temps libre, je suis presque trop paresseux pour refactoriser cela. Mauvaise nouvelle pour la productivité.
Marcin
71
Il y a beaucoup de «contre» dans les réponses, mais j'aimerais aussi voir de bons exemples de cas où le modèle est bon, pour contraster avec le mauvais ...
DGM
50
J'ai écrit un article de blog sur le sujet il y a quelques mois: jalf.dk/blog/2010/03/… - et permettez-moi de le dire franchement. Je ne peux pas personnellement penser à une seule situation où un singleton est la bonne solution. Cela ne signifie pas qu'une telle situation n'existe pas, mais ... les qualifier de rares est un euphémisme.
jalf
8
@AdamSmith cela ne signifie pas que vous devez le faire, mais cela signifie que vous pouvez y accéder comme ça. Et si vous n'avez pas l'intention d'y accéder comme ça, alors il n'y a pas de raison d'en faire un singleton en premier lieu. Donc votre argument est effectivement "il n'y a pas de mal à faire un singleton si nous ne le traitons pas comme un singleton. Ouais, super. Ma voiture ne pollue pas non plus si je n'y conduis pas. Mais alors il est plus facile de simplement pas acquérir une voiture en premier lieu.;) (divulgation complète: je n'ai pas vraiment de voiture)
jalf
35
Le pire de tout ce sujet est que les gens qui détestent les singletons donnent rarement des suggestions concrètes sur ce qu'il faut utiliser à la place. Les liens vers des articles de revues et des blogs auto-publiés tout au long de cet article SO, par exemple, expliquent pourquoi ne pas utiliser des singletons (et ils sont tous d'excellentes raisons), mais ils sont extrêmement minces sur les remplacements. Beaucoup d'ondulations, cependant. Ceux d'entre nous qui essayent d'enseigner aux nouveaux programmeurs pourquoi ne pas utiliser des singletons n'ont pas beaucoup de bons contre-exemples tiers à signaler, seulement des exemples artificiels. C'est fatigant.
Ti Strga

Réponses:

1294

Paraphrasé de Brian Button:

  1. Ils sont généralement utilisés comme une instance globale, pourquoi est-ce si mauvais? 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 passer est une odeur de code .

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

  3. Ils provoquent par nature un couplage étroit du code . Cela rend leur simulation sous test assez difficile dans de nombreux cas.

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

Jim Burger
la source
324
Je ne suis pas d'accord avec vous. Étant donné que les commentaires ne sont autorisés que pour 600 caractères, j'ai écrit un billet de blog pour commenter cela, veuillez consulter le lien ci-dessous. jorudolph.wordpress.com/2009/11/22/singleton-considerations
Johannes Rudolph
61
Aux points 1 et 4, je pense que les singletons sont utiles, et en fait presque parfaits pour la mise en cache des données (en particulier à partir d'une base de données). L'augmentation des performances dépasse largement la complexité de la modélisation des tests unitaires.
Dai Bok
56
@Dai Bok: "mise en cache des données (en particulier à partir d'une base de données)" utilisez le modèle de proxy pour ce faire ...
paxos1977
55
Wow, d'excellentes réponses. J'ai probablement utilisé un libellé trop agressif ici, alors n'oubliez pas que je répondais à une question négative. Ma réponse était censée être une courte liste des «anti-patterns» qui se produisent suite à une mauvaise utilisation de Singleton. Divulgation complète; J'utilise moi aussi des Singletons de temps en temps. Il y a des questions plus neutres sur le SO qui feraient d'excellents forums pour savoir quand les singletons peuvent être considérés comme une bonne idée. Par exemple, stackoverflow.com/questions/228164/…
Jim Burger
21
Ils ne sont pas parfaits pour la mise en cache dans un environnement multithread. Vous pouvez facilement vaincre un cache avec plusieurs threads se disputant une ressource limitée. [maintenu par un singleton]
monksy
449

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

Contention de ressources.

Si vous avez une ressource qui

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

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

vous avez besoin d'un singleton .

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

Il est rare que vous ayez besoin d'un singleton. La raison pour laquelle ils sont mauvais, c'est qu'ils se sentent comme un global et qu'ils sont un membre à part entière du livre GoF Design Patterns .

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

S.Lott
la source
43
Le matériel est également un exemple non? Les systèmes embarqués ont beaucoup de matériel qui pourrait utiliser des singletons - ou peut-être un gros? <grin>
Jeff
170
Entièrement d'accord. Il y a beaucoup de discours déterminés "cette pratique est mauvaise" flottant sans aucune reconnaissance que la pratique peut avoir sa place. Souvent, la pratique n'est que "mauvaise" car elle est souvent mal utilisée. Il n'y a rien de fondamentalement mauvais avec le modèle Singleton tant qu'il est appliqué de manière appropriée.
Damovisa
53
Les singletons réels, par principe, sont très rares (et une file d'attente d'imprimantes n'en est certainement pas une, et aucun fichier journal non plus - voir log4j). Le plus souvent, le matériel est un singleton par coïncidence plutôt que par principe. Tout le matériel connecté à un PC est au mieux un singleton fortuit (pensez à plusieurs moniteurs, souris, imprimantes, cartes son). Même un détecteur de particules de 500 millions de dollars est un singleton par coïncidence et contraintes budgétaires - qui ne s'appliquent pas au logiciel, donc: pas de singleton. Dans les télécommunications, ni le numéro de téléphone ni le téléphone physique ne sont des singletons (pensez RNIS, centre d'appels).
digitalarbeiter
23
Le matériel peut n'avoir qu'une seule instance d'une variété de ressources, mais le matériel n'est pas un logiciel. Il n'y a aucune raison qu'un port série unique sur une carte de développement soit modélisé comme un Singleton. En effet, le modéliser ainsi ne fera que rendre plus difficile le portage vers la nouvelle carte qui a deux ports!
dash-tom-bang
19
Donc, vous écririez deux classes identiques, en dupliquant beaucoup de code, juste pour avoir deux singletons représentant deux ports? Que diriez-vous d'utiliser simplement deux objets SerialPort globaux? Que diriez-vous de ne pas modéliser le matériel en tant que classes? Et pourquoi utiliseriez-vous des singletons, qui impliquent également un accès global? Voulez-vous que chaque fonction de votre code puisse accéder au port série?
jalf
352

Certains snobs de codage les considèrent comme un simple monde glorifié. De la même manière que beaucoup de gens détestent la déclaration goto , il y en a 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 n'est qu'une technique de programmation qui est une partie utile de votre boîte à outils de concepts. De temps en temps, vous pourriez trouver que c'est la solution idéale et donc l'utiliser. Mais l'utiliser juste pour que vous puissiez vous vanter d'utiliser un modèle de conception est tout aussi stupide que de ne jamais l'utiliser parce que c'est juste un global .

Phil Wright
la source
17
L'échec que je vois à Singleton est que les gens les utilisent au lieu des globaux parce qu'ils sont en quelque sorte «meilleurs». Le problème est (comme je le vois), que les choses que Singleton apporte à la table dans ces cas ne sont pas pertinentes. (Construct-on-first-use est trivial à implémenter dans un non-singleton, par exemple, même s'il n'utilise pas réellement le constructeur pour le faire.)
dash-tom-bang
21
La raison pour laquelle «nous» les méprisons est que «nous» les voyons très souvent mal utilisés, et bien trop souvent. "Nous" savons qu'ils ont leur cause.
Bjarke Freund-Hansen
5
@Phil, vous avez déclaré "de temps en temps, vous pourriez trouver que c'est la solution idéale et donc l'utiliser". Ok, alors exactement dans quel cas trouverions-nous un singleton utile?
Pacerier
22
@Pacerier, lorsque toutes les conditions suivantes sont réunies: (1) vous n'avez besoin que de quelque chose, (2) vous devez passer cette chose comme argument dans un grand nombre d'appels de méthode, (3) vous êtes prêt à accepter un chance d'avoir à refactoriser un jour en échange d'une réduction immédiate de la taille et de la complexité de votre code en ne passant pas le sacré truc partout.
antinome
18
Je ne pense pas que cela réponde à quoi que ce soit, cela dit simplement que "parfois cela peut convenir, d'autres fois cela peut ne pas". D'accord, mais pourquoi et quand? Qu'est-ce qui rend cette réponse plus qu'un argument de modération ?
Guildenstern
219

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

Les singletons sont des menteurs pathologiques a un exemple de test unitaire qui illustre comment les singletons peuvent rendre difficile la détermination 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 fait est toujours valable:

Les singletons ne sont rien de plus qu'un état global. L'état global permet à vos objets de se procurer secrètement des choses qui ne sont pas déclarées dans leurs API et, par conséquent, les singletons font de vos API des menteurs pathologiques.

Là où tous les singletons sont partis, le fait que l'injection de dépendances a facilité l'obtention des instances aux constructeurs qui en ont besoin, ce qui atténue le besoin sous-jacent derrière les mauvais singletons mondiaux décriés dans le premier article.

jason
la source
8
Les articles de Misko sur le sujet sont pour le moment la meilleure chose à faire.
Chris Mayer
22
Le premier lien ne résout pas réellement un problème avec les singletons, mais suppose plutôt une dépendance statique à l'intérieur de la classe. Il est possible de corriger l'exemple donné en passant des paramètres, tout en utilisant des singletons.
DGM
17
@DGM: Exactement - en fait, il y a un énorme décalage logique entre la partie «justification» de l'article et la partie «Les singletons sont la cause».
Harper Shelby
1
L'article CreditCard de Misko est un exemple extrême d'utilisation abusive de ce modèle.
Alex
2
En lisant le deuxième article, les singletons font en fait partie du modèle objet décrit. Cependant, au lieu d'être accessibles globalement, ils sont privés des objets Factory.
FruitBreak
121

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 sur ce point. Singleton n'est pas un modèle pour envelopper les mondiaux. Le modèle singleton ne doit être utilisé que pour garantir qu'une et une seule instance d'une classe donnée existe pendant l'exécution.

Les gens pensent que Singleton est mauvais parce qu'ils l'utilisent pour les mondiaux. C'est à cause de cette confusion que Singleton est méprisé. S'il vous plaît, ne confondez pas singletons et globaux. S'il est utilisé dans le but pour lequel il a été conçu, vous tirerez des avantages extrêmes du modèle Singleton.

Cem Catikkas
la source
20
Quelle est cette instance, disponible dans toute l'application? Oh. Global . "Singleton n'est pas un modèle pour envelopper les globaux" est soit naïf soit trompeur, car par définition , le modèle enveloppe une classe autour d'une instance globale.
cHao
26
Bien sûr, vous êtes libre de créer une instance de la classe au démarrage de votre application et d'injecter cette instance, via une interface, dans tout ce qui l'utilise. L'implémentation ne devrait pas se soucier du fait qu'il ne peut y en avoir qu'un.
Scott Whitlock
4
@Dainius: Il n'y en a vraiment pas, au final. Bien sûr, vous ne pouvez pas remplacer arbitrairement l'instance par une autre. (Sauf pour les moments où vous faites face à vous-même . J'ai déjà vu des setInstanceméthodes.) état mondial mutable, alors il a utilement (?) fourni des poseurs pour tous. Célibataire. champ. (Et oui, cela arrive. Beaucoup . Presque tous les singleton que j'ai jamais vus dans la nature étaient mutables par conception, et souvent de manière embarrassante.)
cHao
4
@Dainius: Dans une large mesure, nous l'avons déjà. "Préférez la composition à l'héritage" est une chose qui fait un bon moment maintenant. Lorsque l'héritage est manifestement la meilleure solution, vous êtes bien sûr libre de l'utiliser. Même chose avec les singletons, les globales, le filetage, gotoetc. Ils peuvent fonctionner dans de nombreux cas, mais franchement, "ça marche" ne suffit pas - si vous voulez aller à l'encontre de la sagesse conventionnelle, vous feriez mieux de pouvoir démontrer comment votre approche est meilleur que les solutions conventionnelles. Et je n'ai pas encore vu un tel cas pour le motif Singleton.
cHao
3
De peur que nous ne nous parlions les uns aux autres, je ne parle pas seulement d'une instance disponible à l'échelle mondiale. Il existe de nombreux cas pour cela. Ce dont je parle (en particulier quand je dis "capital-S Singleton") est le modèle Singleton du GoF, qui intègre cette seule instance globale dans la classe elle-même, l'expose via une getInstanceméthode ou un nom similaire, et empêche l'existence d'un deuxième instance. Franchement, à ce stade, vous pourriez tout aussi bien ne pas avoir la seule instance.
cHao du
72

Une mauvaise chose à propos des singletons est que vous ne pouvez pas les étendre très facilement. Vous devez essentiellement construire une sorte de motif de décoration ou quelque chose de ce genre si vous voulez changer leur comportement. De plus, si un jour vous voulez avoir plusieurs façons de faire cette chose, cela peut être assez douloureux de changer, selon la façon dont vous disposez votre code.

Une chose à noter, si vous utilisez des singletons, essayez de les transmettre à ceux qui en ont besoin plutôt que de les faire accéder directement ... Sinon, si vous choisissez d'avoir plusieurs façons de faire la chose que singleton fait, ce sera assez 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 est appelé injection de dépendance et est généralement considéré comme une bonne chose.

Comme tout modèle cependant ... Pensez-y et demandez-vous si son utilisation dans la situation donnée est inappropriée ou non ... Les règles sont faites pour être brisées généralement, et les modèles ne doivent pas être appliqués volontairement sans réfléchir.

Mike Stone
la source
17
Hé, si tu fais ça partout, alors tu devrais faire circuler une référence au singelton partout aussi, et donc tu n'as plus de singleton. :) (Ce qui est généralement une bonne chose OMI.)
Bjarke Freund-Hansen
2
@ BjarkeFreund-Hansen - Nonsense, de quoi tu parles? Un singleton est simplement une instance d'une classe qui est instanciée une fois. Référencer un tel Singleton ne copie pas l'objet réel, il le fait simplement référence - vous avez toujours le même objet (lire: Singleton).
M. Mimpen
2
@ M.Mimpen: Non, un singleton capital-S (qui est ce qui est discuté ici) est une instance d'une classe qui (a) garantit qu'une seule instance existera jamais, et (b) est accessible via la classe propre point d'accès global intégré. Si vous avez déclaré que rien ne devrait être appelé getInstance(), alors (b) n'est plus tout à fait vrai.
cHao
2
@cHao Je ne vous suis pas ou vous ne comprenez pas à qui je commente - c'est à Bjarke Freund-Hansen. Bjarke déclare que le fait d'avoir plusieurs références d'un singleton donne plusieurs singletons. Ce n'est certainement pas vrai car il n'y a pas de copies complètes.
M. Mimpen
6
@ M.Mimpen: Je profite de son commentaire pour parler davantage de l'effet sémantique. Une fois que vous avez interdit les appels à getInstance(), vous avez effectivement éliminé la seule différence utile entre le modèle Singleton et une référence ordinaire. Pour le reste du code, l'unicité n'est plus une propriété. Seul l'appelant a getInstance()besoin de savoir ou même de se soucier du nombre d'instances. Avec un seul appelant, il en coûte plus d'efforts et de flexibilité pour que la classe applique de manière fiable l'unicité que pour que l'appelant stocke simplement une référence et la réutilise.
cHao
69

Le motif singleton n'est pas un problème en soi. Le problème est que le modèle est souvent utilisé par les personnes développant des logiciels avec des outils orientés objet sans avoir une solide compréhension des concepts OO. Lorsque des singletons sont introduits dans ce contexte, ils ont tendance à se transformer en 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. L'inversion de contrôle (IoC) et l' injection de dépendances sont des modèles destinés à surmonter ce problème d'une manière orientée objet qui se prête aux tests unitaires.

Dans un environnement poubelle, les singletons peuvent rapidement devenir un problème de gestion de la mémoire.

Il existe également le scénario multi-thread où les singletons peuvent devenir un goulot d'étranglement ainsi qu'un problème de synchronisation.

Kimoz
la source
4
je sais que c'est un fil de plusieurs années. salut @Kimoz u a déclaré: - les singletons peuvent rapidement devenir un problème en ce qui concerne la gestion de la mémoire. aimerait expliquer plus en détail quel type de problème peut arriver concernant le singleton et la collecte des ordures.
Thomas
@ Kimoz, la question est de savoir "Pourquoi le motif singleton n'est-il pas un problème en soi?" et vous avez simplement répété le point mais n'avez même pas fourni un seul cas d'utilisation valable du modèle singleton.
Pacerier
@Thomas, car un singleton par définition n'existe que dans une seule instance. Il est donc souvent complexe d'attribuer la seule référence à null. Cela peut être fait, mais cela signifie que vous contrôlez complètement le point après lequel le singleton n'est pas utilisé dans votre application. Et c'est rare, et généralement tout à fait le contraire de ce que recherchent les amateurs de singleton: un moyen simple de rendre une seule instance toujours accessible. Sur certains cadres DI comme Guice ou Dagger, il n'est pas possible de se débarrasser d'un singleton et il reste à jamais en mémoire. (Bien que les singletons fournis en conteneur soient bien meilleurs que ceux faits maison).
Snicolas
54

Un singleton est implémenté à l'aide d'une méthode statique. Les personnes qui font des tests unitaires évitent les méthodes statiques car elles ne peuvent pas être moquées ou écrasées. La plupart des gens sur ce site sont de grands partisans des tests unitaires. La convention généralement la plus acceptée pour les éviter est d'utiliser l' inversion du modèle de contrôle .

Peter Mortensen
la source
9
Cela ressemble plus à un problème avec les tests unitaires qui peuvent tester des objets (unités), des fonctions (unités), des bibliothèques entières (unités), mais échouent avec quelque chose de statique en classe (également des unités).
v010dya
2
n'êtes-vous pas supposé de toute façon moc toutes les références externes? Si c'est le cas, quel est le problème pour moc singleton, sinon, faites-vous vraiment des tests unitaires?
Dainius
@Dainius: Les instances de simulation sont beaucoup moins problématiques que les classes de simulation . Vous pouvez éventuellement extraire la classe sous test du reste de l'application et tester avec une fausse Singletonclasse. Cependant, cela complique énormément le processus de test. D'une part, vous devez maintenant pouvoir décharger les classes à volonté (ce n'est pas vraiment une option dans la plupart des langues), ou démarrer une nouvelle machine virtuelle pour chaque test (lire: les tests peuvent prendre des milliers de fois plus longtemps). Pour deux, cependant, la dépendance Singletonest un détail d'implémentation qui fuit maintenant partout dans vos tests.
cHao
Powermock peut se moquer de choses statiques.
Snicolas
se moquer d'un objet signifie-t-il créer un objet réel? Si la moquerie ne crée pas un objet réel, alors pourquoi est-ce important que la classe soit singleton ou que la méthode soit statique?
Arun Raaj
45

Les singletons sont également mauvais en matière 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 n'entrent pas en conflit, 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'il n'existe qu'un seul singleton dans votre application et que toutes les bases de données passent par celui-ci et seulement SingletonDao . Votre environnement de production ressemble maintenant à ceci: Singleton unique

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 soudain quelque chose comme ça:

De nombreux singletons

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

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

Uooo
la source
4
si vous ne savez pas comment implémenter singleton, vous ne devriez pas le faire. Si vous ne savez pas ce que vous faites, vous devriez le trouver en premier, et seulement après cela, faire ce dont vous avez besoin.
Dainius
3
C'est intéressant, j'ai une question. Alors, quel est exactement le problème si des singletons - chacun sur une machine / JVM différente - se connectent à une seule base de données? La portée des singletons est uniquement pour cette machine virtuelle Java particulière, et cela est toujours vrai même dans un cluster. Plutôt que de simplement dire philosophiquement que cette situation particulière est mauvaise parce que notre intention était un objet unique à travers l'application, je serais heureux de voir tous les problèmes techniques qui peuvent survenir à cause de cet arrangement.
Saurabh Patil
39
  1. Il est facilement (ab) utilisé comme variable globale.
  2. Les classes qui dépendent de singletons sont relativement plus difficiles à tester unitairement isolément.
jop
la source
33

Le monopole est le diable et les singletons avec un état non en lecture seule / mutable sont le `` vrai '' problème ...

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

Global est mauvais parce que:

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

En ce qui concerne les singletons

  • une. La façon explicite OO de les appeler empêche les conflits, alors pointez a. n'est pas un problème
  • b. Les singletons sans état ne sont pas (comme les usines) un problème. Les singletons avec état peuvent à nouveau appartenir à deux catégories, celles qui sont immuables ou écrivent une seule fois et en lisent plusieurs (fichiers de configuration / propriété). Ce ne sont pas mauvais. Les singletons Mutable, qui sont en quelque sorte des détenteurs de références, sont ceux dont vous parlez.

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

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

Pour commencer un jeu de monopole, d'abord:

  • nous établissons d'abord les règles pour que tout le monde soit sur la même longueur d'onde
  • tout le monde a un départ égal 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 quiconque n'a 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 attentivement le reste des joueurs terminer le jeu, et les pertes sont généralement rapides 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.

Vous jouez donc en monopole avec des amis Bob, Joe et Ed. Vous construisez rapidement votre empire et consommez des parts de marché à un rythme exponentiel. Vos adversaires s'affaiblissent et vous commencez à sentir le sang (au sens figuré). Votre copain Bob a investi tout son argent dans le blocage du plus grand nombre possible de propriétés de faible valeur, mais le sien ne reçoit pas un retour sur investissement élevé comme il s'y attendait. Bob, comme un coup de malchance, atterrit sur votre Boardwalk et est retiré du jeu.

Maintenant, le jeu passe du lancer de dés amical aux affaires sérieuses. Bob est devenu un exemple d'échec et Joe et Ed ne veulent pas finir comme «ce gars». Donc, étant le principal acteur, vous devenez tout d'un coup l'ennemi. Joe et Ed commencent à pratiquer des échanges sous la table, des injections d'argent dans le dos, des échanges de maisons sous-évalués et généralement tout ce qui vous affaiblit en tant que joueur jusqu'à ce que l'un d'eux atteigne le sommet.

Puis, au lieu que l'un d'eux gagne, le processus recommence. Tout d'un coup, un ensemble fini de règles devient une cible mouvante et le jeu dégénère en le type d'interactions sociales qui constitueraient le fondement de chaque émission de télé-réalité de haut niveau 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 personne pour prendre les décisions. À ce stade, chaque joueur du jeu établit ses propres règles et le chaos s'ensuit jusqu'à ce que deux des joueurs soient trop fatigués pour continuer la mascarade et abandonner lentement.

Donc, si un livre de règles pour un jeu représentait fidèlement un singleton, le livre de règles monopolistique serait un exemple d'abus.

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

Mis à part tous les problèmes évidents de sécurité des threads et de synchronisation que les singletons mutables présentent ... c'est probablement le bon moment pour prendre du recul et demander "est-ce que j'utilise 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 cross-thread torsadé dans une application. Ayant travaillé directement sur le code, je peux attester qu'il s'agissait d'un ralentissement (en raison de tous les verrous de threads nécessaires pour le rendre sûr pour les threads) et d'un cauchemar sur lequel travailler (en raison de la nature imprévisible / intermittente des bogues de synchronisation), et presque impossible à tester dans des conditions de «production». Bien sûr, un système aurait pu être développé en utilisant l'interrogation / signalisation pour surmonter certains des problèmes de performances, mais cela ne résoudrait pas les problèmes avec les tests et, pourquoi s'embêter quand une «vraie» base de données peut déjà accomplir la même fonctionnalité dans un environnement beaucoup plus robuste / de manière évolutive.

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

Evan Plaice
la source
1
Et si singleton encaisse certaines données?
Yola
@Yola Cela réduirait le nombre d'écritures si le singleton devait être mis à jour selon un calendrier prédéterminé et / ou fixe, réduisant ainsi la contention des threads. Pourtant, vous ne seriez pas en mesure de tester avec précision le code interagissant avec le singleton à moins que vous ne vous moquiez d'une instance non singleton qui simule le même usage. Les gens de TDD auraient probablement un ajustement mais cela fonctionnerait.
Evan Plaice
@EvanPlaice: Même avec une maquette, vous auriez des problèmes avec le code qui dit Singleton.getInstance(). Un langage qui prend en charge la réflexion peut être en mesure de contourner cela en définissant le champ où la One True Instance est stockée. IMO, cependant, les tests deviennent un peu moins dignes de confiance une fois que vous vous êtes familiarisé avec l'état privé d'une autre classe.
cHao
28

Singleton n'est pas une instance unique!

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

  • Problème : Singleton peut être un défi dans un environnement multithread
    Solution : Utilisez un processus d'amorçage à thread unique pour initialiser toutes les dépendances de votre singleton.
  • Problème : il est difficile de se moquer des singletons.
    Solution : utilisez la méthode Modèle d' usine pour se moquer

Vous pouvez mapper MyModelà la TestMyModelclasse qui en hérite, partout où MyModelsera injecté vous obtiendrez TestMyModelinstread. - Problème : les singletons peuvent provoquer des fuites de mémoire car ils n'ont jamais été éliminés.
Solution : Eh bien, jetez-les! Implémentez un rappel dans votre application pour éliminer correctement les singletons, vous devez supprimer toutes les données qui leur sont liées et enfin: les supprimer de l'usine.

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

  • Singletons améliore la lisibilité : vous pouvez regarder votre classe et voir quel singleton il a injecté pour comprendre 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 de singleton, vous n'avez pas besoin d'aller modifier un gros lien d'autres classes qui vient de déplacer votre dépendance (c'est du code qui pue pour moi @Jim Burger )
  • Singletons améliore la mémoire et les performances : lorsque quelque chose se produit dans votre application et qu'il faut une longue chaîne de rappels à livrer, vous gaspillez de la mémoire et des performances.En utilisant Singleton, vous coupez l'homme du milieu et améliorez vos performances et votre utilisation de la mémoire ( en évitant les allocations inutiles de variables locales).
Ilya Gazman
la source
2
Cela ne résout pas mon problème principal avec les singletons qui permettent d'accéder à l'état global à partir de n'importe laquelle des milliers de classes de votre projet.
LegendLength
8
Ce serait le but ...
Ilya Gazman
LegendLength Pourquoi est-ce mal? Par exemple, dans mon application, j'ai un Settingsobjet singleton qui est accessible à partir de n'importe quel widget afin que chaque widget sache comment formater les nombres affichés. Si ce n'était pas un objet accessible globalement, je devrais l'injecter dans le constructeur à chaque widget du constructeur et garder la référence à lui en tant que variable membre. C'est une terrible perte de mémoire et de temps.
VK
23

Ma réponse sur la façon dont les singletons sont mauvais est toujours "ils sont difficiles à bien faire". De nombreux composants fondamentaux des langages sont des singletons (classes, fonctions, espaces de noms et même opérateurs), tout comme les composants d'autres aspects de l'informatique (hôte local, route par défaut, système de fichiers virtuel, etc.), et ce n'est pas par accident. Bien qu'ils causent des ennuis et de la frustration de temps en temps, ils peuvent aussi améliorer beaucoup de choses.

Les deux plus gros défauts 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 globaux, car ils le sont essentiellement. Cependant, une grande partie (malheureusement, pas tous) de la méchanceté dans un global ne vient pas intrinsèquement d'être global, mais de la façon dont vous l'utilisez. Il en va de même pour les singletons. En fait, d'autant plus que "instance unique" n'a pas vraiment besoin de signifier "globalement accessible". C'est plus un sous-produit naturel, et étant donné tout le mal que nous savons en provient, nous ne devrions pas être si 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 devez y accéder comme vous le feriez pour tout autre objet. La plupart des codes ne devraient même pas être conscients qu'il s'agit d'un Singleton (couplage lâche, non?). 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.

Le contexte Singleton est également très important. La caractéristique qui définit un Singleton est qu'il n'y en a "qu'un", mais la vérité est qu'il n'est "qu'un" dans une sorte de contexte / espace de noms. Ils sont généralement l'un des: un par thread, processus, adresse IP ou cluster, mais peut également être un par processeur, machine, espace de noms de langage / chargeur de classe / autre, sous-réseau, Internet, etc.

L'autre erreur, moins courante, est d'ignorer le mode de vie Singleton. Le simple fait qu'il n'y en ait qu'un ne signifie pas qu'un Singleton est omnipotent "a toujours été et sera toujours", et n'est généralement pas souhaitable (les objets sans début ni fin violent toutes sortes d'hypothèses utiles dans le code et ne doivent être utilisés que dans les circonstances les plus désespérées.

Si vous évitez ces erreurs, les Singletons peuvent toujours être un PITA, mais il est prêt à voir que beaucoup des pires problèmes sont considérablement atténués. Imaginez un Java Singleton, qui est explicitement défini comme 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 qui dicte quand et comment ils doivent être invoqués, et dont la méthode "instance" a protection du package afin qu'il soit généralement accessible via d'autres objets non globaux. Encore une source potentielle de problèmes, mais certainement beaucoup moins de problèmes.

Malheureusement, plutôt que d'enseigner de bons exemples sur la façon de faire des singletons. Nous enseignons de mauvais exemples, laissons les programmeurs s'en servir pendant un certain temps, puis leur disons que c'est un mauvais modèle de conception.

Christopher Smith
la source
23

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 des situations où une seule instance d'une classe n'est pas réellement requise. [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 mauvais , mai 2004
  3. ^ Steve Yegge. Singletons considérés comme stupides , septembre 2004
  4. ^ JB Rainsberger, IBM. Utilisez vos singletons à bon escient , juillet 2001
GUI Junkie
la source
8
Une description du motif n'explique pas pourquoi il est considéré comme diabolique ...
Jrgns
2
À peine juste: "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 des situations où une seule instance d'une classe n'est pas réellement requise." Regardez les références ... Quoi qu'il en soit, il y a RTFM pour moi.
GUI Junkie
17

Ce n'est pas que les singletons eux-mêmes sont mauvais, mais le modèle de conception du GoF l'est. Le seul argument vraiment valable est que le modèle de conception du GoF ne se prête pas aux tests, surtout si les tests sont exécutés en parallèle.

L'utilisation d'une seule instance 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 comme singleton implémente une interface. Cela permet aux stubs ou aux mocks d'être implémentés en utilisant la même interface

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

  3. Le singleton doit être de nature simple et pas trop compliqué.

  4. Pendant 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 passer l'instance singleton à la classe qui en a besoin.

  5. Pendant les tests et pour garantir un comportement déterministe, créez la classe singleton en tant qu'instance distincte soit la classe réelle elle-même, soit un stub / mock qui implémente son comportement et le transmettez tel quel à la classe qui le requiert. N'utilisez pas le facteur de classe qui crée cet objet sous test qui a besoin du singleton pendant le test car il en transmettra l'instance globale unique, ce qui va à l'encontre du but.

Nous avons utilisé des singletons dans nos solutions avec beaucoup de succès qui peuvent être testés, garantissant un comportement déterministe dans des flux de tests parallèles.

utilisateur1578119
la source
+1, enfin une réponse qui indique quand un singleton peut être valide.
Pacerier
16

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

  1. Pourquoi masquer les dépendances dans votre code est-il mauvais? Il existe déjà des dizaines de dépendances cachées (appels d'exécution C, appels d'API OS, appels de fonction globale) et les dépendances singleton sont faciles à trouver (recherchez par exemple ()).

    "Faire quelque chose de global pour éviter de le faire passer est une odeur de code." Pourquoi ne passe-t-on pas 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 bien?

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

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

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

Concernant les tests unitaires:

  • toutes les classes n'ont pas besoin d'être testées à l'unité
  • toutes les classes qui doivent être testées unitairement ne doivent pas changer l'implémentation du singleton
  • si elles font besoin l' unité testé et avez besoin de changer la mise en œuvre, il est facile de changer une classe d'utiliser un singleton pour avoir le singleton lui a été transmis par l' injection de dépendance.
Jon
la source
1
1. Toutes ces dépendances cachées? Ce sont mauvais aussi. Les dépendances cachées sont toujours mauvaises. Mais dans le cas du CRT et du système d'exploitation, ils sont déjà là et ils sont le seul moyen de faire quelque chose. (Essayez d'écrire un programme C sans utiliser le runtime ou le système d'exploitation.) Cette capacité à faire des choses l'emporte largement sur leurs points négatifs. Les singletons dans notre code n'obtiennent pas ce luxe; puisqu'ils sont fermement dans notre sphère de contrôle et de responsabilité, chaque utilisation (lire: chaque dépendance cachée supplémentaire) devrait être justifiée comme le seul moyen raisonnable de faire avancer les choses. Très, très peu d'entre eux le sont réellement.
cHao
2. La "responsabilité" est généralement définie comme une "raison de changer". Un singleton finit par gérer sa vie et faire son vrai travail. Si vous changez la façon dont le travail est effectué ou la façon dont le graphique d'objet est construit, vous devez changer la classe. Mais si vous avez un autre code pour construire le graphe objet, et que votre classe fait juste son vrai travail, ce code d'initialisation peut configurer le graphe objet comme bon lui semble. Tout est beaucoup plus modulaire et testable, car vous pouvez insérer des doubles de test et tout démolir à volonté, et vous ne comptez plus sur des pièces mobiles cachées.
cHao
1
@cHao: 1. C'est bien que vous reconnaissiez que la "capacité de faire des choses l'emporte largement sur leurs points négatifs". Un exemple serait un cadre de journalisation. Il est mauvais d'imposer le passage d'un objet de journalisation global par injection de dépendances à travers des couches d'appels de fonction si cela signifie que les développeurs sont découragés de se connecter. Par conséquent, singleton. 3. Votre point de couplage étroit n'est pertinent que si vous voulez que les clients de la classe contrôlent le comportement via le polymorphisme. Ce n'est souvent pas le cas.
Jon
2
4. Je ne suis pas sûr que "ne peut pas être détruit manuellement" est une implication logique de "ne peut être qu'une seule instance". Si c'est ainsi que vous définissez singleton, nous ne parlons pas de la même chose. Toutes les classes ne doivent pas être testées à l'unité. C'est une décision commerciale, et parfois le temps de mise sur le marché ou les coûts de développement prévalent.
Jon
1
3. Si vous ne voulez pas de polymorphisme, vous n'avez même pas besoin d'une instance. Vous pourriez aussi bien en faire une classe statique, car vous vous liez à un seul objet et à une seule implémentation de toute façon - et au moins, l'API ne vous ment pas autant.
cHao
15

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

Le singleton ne devrait être envisagé que si les trois critères suivants sont satisfaits:

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

Si la propriété de l'instance unique, quand et comment l'initialisation se produit et l'accès global ne sont pas des problèmes, Singleton n'est pas suffisamment intéressant.

js.
la source
14

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

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

Si vous savez que votre application ne changera pas tant que ça, c'est tout à fait acceptable. Sachez simplement que vous devrez peut-être refaçonner les choses si vos besoins changent de manière inattendue (ce qui est assez bien dans la plupart des cas).

Les singletons compliquent parfois les tests unitaires .

tacone
la source
3
D'après mon expérience, commencer par des singletons vous fera vraiment du mal même à court terme, sans compter le long terme. Cet effet pourrait me l'être moins si l'application existe déjà depuis un certain temps, et probablement déjà infestée par d'autres singletons. Vous partez de zéro? Évitez-les à tout prix! Vous voulez une seule instance d'un objet? Laissez une usine gérer l'instanciation de cet objet.
Sven
1
AFAIK Singleton est une méthode d'usine. Je n'ai donc pas votre recommandation.
tacone
3
"Une usine"! = "Une méthode d'usine qui ne peut pas être séparée des autres trucs utiles de la même classe"
Sven
13

Il n'y a rien de fondamentalement mauvais avec le modèle, en supposant qu'il soit utilisé pour un aspect de votre modèle qui est vraiment unique.

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

Ben Hoffstein
la source
6
Je pense que le contrecoup a plus à voir avec les gens qui pratiquent les tests unitaires formalisés se rendant compte qu'ils sont un cauchemar à traiter.
Jim Burger
1
Je ne sais pas pourquoi c'est à -1. Ce n'est pas la réponse la plus descriptive mais il n'a pas tort non plus.
Outlaw Programmer
13

Je ne vais pas commenter l'argument du bien / du mal, mais je ne les ai pas utilisés depuis l' arrivée du printemps . L'utilisation de l'injection de dépendances a pratiquement supprimé mes exigences pour les singleton, les servicelocators et les usines. Je trouve que c'est un environnement beaucoup plus productif et propre, au moins pour le type de travail que je fais (applications Web basées sur Java).

Peter Mortensen
la source
3
les haricots de printemps, par défaut, ne sont-ils pas des singletons?
slim
3
Oui, mais je veux dire des singletons de «codage». Je n'ai pas «écrit un singleton» (c'est-à-dire avec un constructeur privé yada yada yada selon le modèle de conception) - mais oui, avec spring j'utilise une seule instance.
prule
4
donc quand les autres le font, c'est Ok (si je vais l'utiliser après), mais si les autres le font et que je ne l'utilise pas, c'est mal?
Dainius
11

Singleton est un modèle et peut être utilisé ou abusé comme tout 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 qu'il n'est pas conçu pour faire). Le plus gros délinquant utilise un singleton comme fausse variable globale.

Loki Astari
la source
1
Merci Loki :) Exactement mon point. Toute la chasse aux sorcières me rappelle le débat goto. Les outils sont destinés aux personnes qui savent les utiliser; utiliser un outil que vous n'aimez pas peut être dangereux pour vous, alors évitez-le, mais NE dites PAS aux autres de ne pas utiliser / de ne pas apprendre à l'utiliser correctement. Je ne suis pas exactement "pro-singleton" mais j'aime le fait que j'ai un outil comme ça et je peux sentir où il convient de l'utiliser. Période.
dkellner
8

Lorsque vous écrivez du code à l'aide de 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 rencontrez des problèmes.

Les singletons font qu'il est très difficile de passer d'eux à des objets normaux.

De plus, 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 enveloppez tous dans un objet d'assistance, 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);
}
Roman Odaisky
la source
4
passer l'argument pour chaque méthode est brillant, il devrait aller au moins dans les 10 meilleures façons de polluer votre API.
Dainius
C'est un inconvénient évident, et qui aurait dû être géré par le langage, au moyen d'arguments qui se propagent en quelque sorte dans des appels imbriqués, mais en l'absence d'un tel support, cela doit être fait manuellement. Considérez que même les singletons naturels, comme un objet représentant l'horloge du système, peuvent poser problème. Par exemple, comment allez-vous couvrir le code dépendant de l'horloge (pensez au compteur d'électricité à tarifs multiples) avec des tests?
Roman Odaisky
dépend de ce que vous testez, si vous ne testez pas singleton, pourquoi vous vous souciez de la façon dont il se comporte, si vos 2 objets distants dépendent les uns des autres, ce n'est pas un problème singleton ..
Dainius
Pourriez-vous indiquer la langue qui se propagerait dans les appels imbriqués?
Dainius
1
Si vous avez un module qui dépend d'un autre et que vous ne le savez pas / ne pouvez pas le mocaliser, vous aurez du mal, qu'il soit singleton ou non. Les gens utilisent souvent l'héritage, où ils devraient utiliser la composition, mais vous ne dites pas que l'héritage est mauvais, et la POO devrait être évitée à tout prix, car tant de gens font des erreurs de conception là-bas, ou êtes-vous?
Dainius
8

Le problème avec les singletons est la question de la portée accrue et donc couplage . Il est indéniable qu'il existe certaines situations où vous avez besoin d'accéder à une seule instance, et cela peut être accompli d'autres façons.

Je préfère maintenant concevoir autour d'une inversion de contrôle conteneur (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 tel exemple que j'ai rencontré récemment était un ajustement facile de simple thread à multi-thread.

FWIW, s'il s'agit d'un 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.

Mark Lindell
la source
7

Les singletons ne sont PAS mauvais. Ce n'est mauvais que lorsque vous créez quelque chose d'unique au niveau mondial qui ne l'est pas au niveau mondial.

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

Vous pouvez ensuite effectuer les opérations suivantes de partout:

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

Et, bien sûr, faites:

MessageQueue.Current.RegisterReceiver (this);

dans les classes qui implémentent IMessageReceiver.

StormianRootSolver
la source
6
Et si je veux créer une deuxième file d'attente de messages, avec une portée plus petite, pourquoi ne devrais-je pas être autorisé à réutiliser votre code pour le créer? Un singleton empêche cela. Mais si vous veniez de créer une classe de file d'attente de messages régulière, puis de créer une instance globale pour agir en tant que "portée d'application", je pourrais créer une deuxième instance pour une autre utilisation. Mais si vous faites de la classe un singleton, je devrais écrire une deuxième classe de file d'attente de messages.
2010
1
Aussi pourquoi ne devrions-nous pas simplement avoir une CustomerOrderList globale afin que nous puissions l'appeler joliment de n'importe où comme MessageQueue? Je pense que la réponse est la même pour les deux: il s'agit en fait de créer une variable globale.
LegendLength
7

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

Peter Mortensen
la source
beaucoup de gens écrivent du code multi-thread dangereux, cela signifie-t-il que nous devrions éliminer les threads?
Dainius
@Dainius: En fait, oui. OMI, le modèle de concurrence par défaut devrait être multi-processus, avec un moyen pour que deux processus (1) se transmettent facilement les messages et / ou (2) partagent la mémoire selon les besoins. Le filetage est utile si vous voulez tout partager , mais vous ne le voulez jamais vraiment. Il pourrait être imité en partageant tout l'espace d'adressage, mais cela serait également considéré comme un anti-modèle.
cHao
@Dainius: Et bien sûr, cela suppose que la concurrence honnête à la bonté soit nécessaire. Souvent, tout ce que vous voulez, c'est pouvoir faire une chose pendant que vous attendez que le système d'exploitation fasse autre chose. (Mise à jour de l'interface utilisateur lors de la lecture à partir d'un socket, par exemple.) Une API asynchrone décente pourrait rendre inutile le threading complet dans la grande majorité des cas.
cHao
donc si vous avez une énorme matrice de données, que vous avez besoin d'un processus, il est préférable de le faire en un seul thread, car pour beaucoup de gens, cela pourrait mal se passer ..
Dainius
@Dainius: Dans de nombreux cas, oui. (Le filetage peut en fait vous ralentir , si vous ajoutez la synchronisation au mixage. C'est un excellent exemple de pourquoi le multithreading ne devrait pas être la première pensée de la plupart des gens.) Dans d'autres cas, il serait préférable d'avoir deux processus qui partagent juste les trucs nécessaires. Bien sûr, vous devez organiser les processus pour partager la mémoire. Mais franchement, je vois cela comme une bonne chose - bien mieux, au moins, que de passer par défaut au mode tout partager. Cela vous oblige à dire explicitement (et donc, idéalement, à savoir) quelles parties sont partagées, et donc quelles parties doivent être thread-safe.
cHao
6

Voici encore une chose au sujet des singletons que personne n'a encore dit.

Dans la plupart des cas, "singletonity" est un détail d'implémentation pour une classe plutôt que la caractéristique de son interface. L'inversion du conteneur de contrôle peut masquer cette caractéristique aux utilisateurs de classe; il vous suffit de marquer votre classe comme un singleton (avec@Singleton annotation en Java par exemple) et c'est tout; L'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. Il n'y a donc rien de mal avec les singletons IoC.

Les singletons GoF à l'opposé des singletons IoC sont censés exposer la "singletonité" dans l'interface via la méthode getInstance (), et de sorte qu'ils souffrent de tout ce qui précède.

Volodymyr Frolov
la source
3
À mon avis, "singletonity" est un détail d'environnement d'exécution, et ne devrait pas être pris en compte par le programmeur qui a écrit le code de la classe. Il s'agit plutôt d'une considération à faire par la classe USER. seul l'UTILISATEUR sait combien d'instances sont réellement nécessaires.
Earth Engine
5

Les singletons ne sont pas mauvais, si vous les utilisez correctement et de façon minimale . Il existe de nombreux autres bons modèles de conception qui remplacent les besoins de singleton à un moment donné (et donnent également les meilleurs résultats). Mais certains programmeurs ne connaissent pas ces bons modèles et utilisent le singleton pour tous les cas, ce qui le rend mauvais pour eux.

Sriram
la source
Impressionnant! Entièrement d'accord! Mais vous pourriez, et peut-être devriez, élaborer beaucoup plus. Telles que l'élargissement des modèles de conception les plus couramment ignorés et la façon d'utiliser "correctement et au minimum" les singletons. Plus facile à dire qu'à faire ! : P
cregox
Fondamentalement, l'alternative consiste à transmettre des objets via des paramètres de méthode, plutôt que d'y accéder via un état global.
LegendLength
5

Premièrement, une classe et ses collaborateurs devraient d'abord réaliser leur objectif plutôt que de se concentrer sur les personnes à charge. La gestion du cycle de vie (lorsque des instances sont créées et hors de portée) ne doit pas faire partie de la responsabilité des classes. La meilleure pratique acceptée pour cela consiste à créer ou à configurer un nouveau composant pour gérer les dépendances à l'aide de l'injection de dépendance.

Souvent, les logiciels deviennent plus compliqués, il est logique d'avoir plusieurs instances indépendantes de la classe Singleton avec un état différent. Commettre du code pour simplement saisir le singleton est incorrect dans de tels cas. En utilisantSingleton.getInstance() peut être correcte pour les petits systèmes simples, mais cela ne fonctionne pas / échelle quand on peut avoir besoin d'une instance différente de la même classe.

Aucune classe ne doit être considérée comme un singleton, mais plutôt comme une application de son utilisation ou de la façon dont elle est utilisée pour configurer les dépendants. Pour une solution rapide et désagréable, cela n'a pas d'importance - un simple codage dur dit que les chemins de fichiers n'ont pas d'importance mais pour les applications plus grandes, ces dépendances doivent être factorisées et gérées de manière plus appropriée à l'aide de DI.

Les problèmes que singleton causent lors des tests sont un symptôme de leur cas / environnement à usage unique codé en dur. La suite de tests et les nombreux tests sont chacun individuels et séparent quelque chose qui n'est pas compatible avec le codage en dur d'un singleton.

mP.
la source
4

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

Ycros
la source
Si votre classe n'est pas limitée à une seule instance, vous aurez besoin de membres statiques dans votre classe gérés par des sémaphores, ce qui revient à peu près à la même chose! Quelle est votre alternative proposée?
Jeach
J'ai une énorme application avec un "MainScreen" cet écran ouvre de nombreuses petites fenêtres modulaires / non modales / formes d'interface utilisateur. À mon humble avis, je pense que le MainScreen devrait être un singleton afin que, par exemple, un widget quelque part dans un coin éloigné de l'application veuille afficher son état dans la barre d'état du MainScreen, tout ce qu'il a à faire est MainScreen.getInstance (). SetStatus ( "Du texte"); Que proposez-vous comme alternative? Passer MainScreen partout dans l'application ?? : D
Salvin Francis
2
@SalvinFrancis: Ce que je recommanderais, c'est que vous arrêtez d'avoir des objets qui se soucient de choses dont ils ne devraient pas se soucier et que vous vous faufilez dans l'application pour vous amuser. :) Votre exemple serait bien mieux fait avec les événements. Lorsque vous effectuez des événements correctement, un widget n'a même pas à se soucier de l'existence d'un MainScreen; il diffuse simplement "hé, il s'est passé des choses", et tout ce qui s'est abonné à l'événement "des choses s'est passé" (que ce soit un MainScreen, un WidgetTest, ou quelque chose d'autre entièrement!) décide comment il veut répondre. C'est ainsi que la POO est censée être faite de toute façon. :)
cHao
1
@Salvin Considérez à quel point il est difficile de raisonner sur MainScreen lors du débogage s'il est mis à jour «silencieusement» par de nombreux composants. Votre exemple est une raison parfaite pour laquelle les singletons sont mauvais.
LegendLength