it-swarm-eu.dev

Was ist so schlimm an Singletons?

Das Singleton-Muster ist ein voll bezahltes Mitglied des GoF -Musterbuchs , aber es scheint in letzter Zeit eher von der Entwicklerwelt verwaist. Ich benutze immer noch ziemlich viele Singletons, insbesondere für Factory-Klassen , und obwohl Sie ein bisschen vorsichtig mit Multithreading-Problemen sein müssen (wie eigentlich jede Klasse), verstehe ich nicht, warum Sie sind so schrecklich.

Stack Overflow scheint besonders davon auszugehen, dass alle der Meinung sind, dass Singletons böse sind. Warum?

Bitte unterstützen Sie Ihre Antworten mit " Fakten, Referenzen oder spezifischem Fachwissen "

1903
Ewan Makepeace

Umschrieben von Brian Button:

  1. Sie werden im Allgemeinen als globale Instanz verwendet. Warum ist das so schlimm? Weil Sie die Abhängigkeiten Ihrer Anwendung in Ihrem Code verbergen, anstatt sie über die Schnittstellen verfügbar zu machen. Etwas global zu machen, um zu vermeiden, dass es herumgereicht wird, ist ein Code-Geruch .

  2. Sie verletzen das Prinzip der einmaligen Verantwortung : aufgrund der Tatsache, dass sie ihre eigene Kreation und ihren eigenen Lebenszyklus kontrollieren.

  3. Sie bewirken von Natur aus, dass der Code eng verbunden ist gekoppelt . Dies macht es in vielen Fällen schwierig, sie im Test zu fälschen.

  4. Sie tragen den Status für die Lebensdauer der Anwendung. Ein weiterer Hit beim Testen, da Sie möglicherweise eine Situation haben, in der Tests bestellt werden müssen, was für Komponententests ein großes Nein ist. Warum? Weil jeder Komponententest unabhängig vom anderen sein sollte.

1246
Jim Burger

Singletons lösen ein (und nur ein) Problem.

Ressourcenkonflikt.

Wenn Sie eine Ressource haben, die

( 1 ) kann nur eine Instanz haben, und

( 2 ) Sie müssen diese einzelne Instanz verwalten,

sie benötigen einen Singleton .

Es gibt nicht viele Beispiele. Eine Protokolldatei ist die große. Sie möchten nicht nur eine einzelne Protokolldatei verlassen. Sie möchten es richtig spülen, synchronisieren und schließen. Dies ist ein Beispiel für eine einzelne gemeinsam genutzte Ressource, die verwaltet werden muss.

Es ist selten, dass Sie einen Singleton benötigen. Der Grund, warum sie schlecht sind, ist, dass sie sich wie ein global fühlen und ein voll bezahltes Mitglied der GoF sind Design Patterns Buch.

Wenn Sie denken, Sie brauchen eine globale, machen Sie wahrscheinlich einen schrecklichen Designfehler.

434
S.Lott

Einige Coding-Snobs sehen sie nur als verherrlichte Welt an. Ebenso wie viele Menschen die goto - Anweisung hassen, gibt es auch andere, die die Idee hassen, jemals global zu verwenden. Ich habe mehrere Entwickler gesehen, die sich außerordentlich bemüht haben, ein globales zu vermeiden, weil sie erwogen haben, eines als Zugeständnis für ein Scheitern zu verwenden. Komisch aber wahr.

In der Praxis ist das Singleton - Muster nur eine Programmiertechnik, die ein nützlicher Bestandteil Ihres Toolkits von Konzepten ist. Von Zeit zu Zeit finden Sie vielleicht, dass es die ideale Lösung ist, und verwenden Sie sie. Aber es nur zu benutzen, damit Sie sich rühmen können, ein Entwurfsmuster zu verwenden, ist genauso dumm, wie sich zu weigern, es jemals zu benutzen, weil es nur ein globales ist.

334
Phil Wright

Misko Hevery von Google hat einige interessante Artikel zu genau diesem Thema ...

Singletons sind pathologische Lügner enthält ein Unit-Test-Beispiel, das veranschaulicht, wie Singletons es schwierig machen können, Abhängigkeitsketten zu ermitteln und eine Anwendung zu starten oder zu testen. Es ist ein ziemlich extremes Beispiel für Missbrauch, aber der Punkt, den er anführt, ist immer noch gültig:

Singletons sind nichts anderes als ein globaler Staat. Der globale Status macht es möglich, dass Ihre Objekte heimlich auf Dinge zugreifen können, die in ihren APIs nicht deklariert sind, und Singletons macht Ihre APIs daher zu pathologischen Lügnern.

Wo sind die Singletons geblieben? macht den Punkt, dass die Abhängigkeitsinjektion es einfach gemacht hat, Instanzen zu Konstruktoren zu bringen, die sie benötigen, was die zugrunde liegenden Bedürfnisse hinter den schlechten, globalen Singletons mindert, die im ersten Artikel besprochen wurden.

212
jason

Ich denke, die Verwirrung wird durch die Tatsache verursacht, dass die Leute die wahre Anwendung des Singleton-Musters nicht kennen. Ich kann das nicht genug betonen. Singleton ist nicht ein Muster zum Umbrechen von Globalen. Singleton-Muster sollten nur verwendet werden, um sicherzustellen, dass eine und nur eine Instanz einer bestimmten Klasse zur Laufzeit vorhanden ist.

Die Leute denken, Singleton ist böse, weil sie es für Globale verwenden. Wegen dieser Verwirrung wird Singleton herabgesehen. Bitte verwechseln Sie Singletons und Globals nicht. Wenn Sie es für den vorgesehenen Zweck verwenden, profitieren Sie von den Vorteilen des Singleton-Musters.

114
Cem Catikkas

Eine ziemlich schlechte Sache bei Singletons ist, dass man sie nicht so einfach erweitern kann. Sie müssen im Grunde eine Art Dekorationsmuster oder etwas Ähnliches einbauen, wenn Sie ihr Verhalten ändern möchten. Wenn Sie eines Tages mehrere Möglichkeiten haben möchten, dies auf einmal zu tun, kann es sehr schmerzhaft sein, Änderungen vorzunehmen, je nachdem, wie Sie Ihren Code gestalten.

Eine Sache zu beachten, wenn Sie Singletons verwenden, versuchen Sie, sie an jeden weiterzugeben, der sie benötigt, anstatt sie direkt darauf zugreifen zu lassen ... Andernfalls wird es sein, wenn Sie sich jemals für mehrere Möglichkeiten entscheiden, das zu tun, was Singleton tut Ziemlich schwierig zu ändern, da jede Klasse eine Abhängigkeit einbettet, wenn sie direkt auf den Singleton zugreift.

Also im Grunde genommen:

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

eher, als:

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

Ich glaube, diese Art von Muster heißt Abhängigkeitsinjektion und wird im Allgemeinen als eine gute Sache angesehen.

Wie jedes Muster auch ... Denken Sie darüber nach und überlegen Sie, ob seine Verwendung in der gegebenen Situation unangemessen ist oder nicht ... Regeln gelten normalerweise als nicht eingehalten, und Muster sollte nicht ohne weiteres angewendet werden habe gedacht.

72
Mike Stone

Das Singleton-Muster ist an sich kein Problem. Das Problem ist, dass das Muster oft von Leuten verwendet wird, die Software mit objektorientierten Werkzeugen entwickeln, ohne ein solides Verständnis für OO Konzepte zu haben. Wenn Singletons in diesem Zusammenhang eingeführt werden, neigen sie dazu, zu unüberschaubaren Klassen zu werden, die Hilfsmethoden für jede noch so kleine Verwendung enthalten.

Singletons sind auch aus Testsicht ein Problem. Sie machen es schwierig, einzelne Unit-Tests zu schreiben. mkehrung der Kontrolle (IoC) und Abhängigkeitsinjektion sind Muster, mit denen dieses Problem objektorientiert überwunden werden kann und die sich für Komponententests eignen.

In einer Müll gesammelt Umgebung können Singletons schnell zu einem Problem in Bezug auf die Speicherverwaltung werden.

Es gibt auch das Multithread-Szenario, bei dem Singletons sowohl zu einem Engpass als auch zu einem Synchronisationsproblem werden können.

68
Kimoz

Ein Singleton wird mit einer statischen Methode implementiert. Statische Methoden werden von Personen, die Unit-Tests durchführen, vermieden, da sie nicht verspottet oder abgestumpft werden können. Die meisten Leute auf dieser Seite sind große Befürworter von Unit-Tests. Die allgemein gebräuchlichste Konvention, um sie zu vermeiden, ist die Verwendung des Musters Inversion der Kontrolle .

53
jwanagel

Singletons sind auch schlecht, wenn es um Clustering geht. Denn dann haben Sie nicht mehr "genau einen Singleton" in Ihrer Anwendung.

Stellen Sie sich folgende Situation vor: Als Entwickler müssen Sie eine Webanwendung erstellen, die auf eine Datenbank zugreift. Um sicherzustellen, dass sich gleichzeitige Datenbankaufrufe nicht überschneiden, erstellen Sie ein thread-save SingletonDao:

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

Sie sind sich also sicher, dass nur ein Singleton in Ihrer Anwendung vorhanden ist und alle Datenbanken diese und nur SingletonDao durchlaufen. Ihre Produktionsumgebung sieht jetzt so aus: Single Singleton

Bisher ist alles in Ordnung.

Angenommen, Sie möchten mehrere Instanzen Ihrer Webanwendung in einem Cluster einrichten. Jetzt hast du plötzlich so etwas:

Many singletons

Das klingt komisch, aber jetzt haben Sie viele Singletons in Ihrer Anwendung. Und genau das soll ein Singleton nicht sein: Viele Objekte davon haben. Dies ist besonders schlimm, wenn Sie, wie in diesem Beispiel gezeigt, synchronisierte Aufrufe an eine Datenbank vornehmen möchten.

Dies ist natürlich ein Beispiel für eine schlechte Verwendung eines Singleton. Die Botschaft dieses Beispiels lautet jedoch: Sie können sich nicht darauf verlassen, dass Ihre Anwendung genau eine Instanz eines Singletons enthält - insbesondere, wenn es um Clustering geht.

43
Uooo
  1. Es kann leicht (ab) als globale Variable verwendet werden.
  2. Klassen, die von Singletons abhängen, sind im Einzeltest relativ schwer zu testen.
38
jop

Monopoly ist der Teufel und Singletons mit nicht schreibgeschütztem/veränderlichem Status sind das "wahre" Problem ...

Nach dem Lesen von Singletons sind pathologische Lügner , wie in Jasons Antwort vorgeschlagen, stieß ich auf diesen kleinen Leckerbissen, der das am besten präsentierte Beispiel für how liefert = Singletons werden oft missbraucht.

Global ist schlecht, weil:

  • ein. Dies führt zu einem Namespace-Konflikt
  • b. Es enthüllt den Zustand in ungerechtfertigter Weise

Wenn es um Singletons geht

  • ein. Die explizite OO Art, sie aufzurufen, verhindert die Konflikte, also zeige a. ist kein Problem
  • b. Singletons ohne Staat sind (wie Fabriken) kein Problem. Singletons mit Status können wieder in zwei Kategorien unterteilt werden, die unveränderlich sind oder einmal schreiben und viele lesen (Konfigurations-/Eigenschaftendateien). Das ist nicht schlecht. Mutable Singletons, die Art von Referenzinhabern sind, sind diejenigen, von denen Sie sprechen.

In der letzten Aussage bezieht er sich auf das Konzept des Blogs "Singletons sind Lügner".

Wie gilt dies für Monopoly?

So starten Sie ein Monopolspiel:

  • wir stellen zuerst die Regeln auf, damit alle auf der gleichen Seite sind
  • jeder erhält zu Beginn des Spiels einen gleichberechtigten Start
  • es wird nur ein Regelsatz vorgestellt, um Verwirrung zu vermeiden
  • die Regeln dürfen sich während des Spiels nicht ändern

Nun, für alle, die nicht wirklich Monopol gespielt haben, sind diese Standards im besten Fall ideal. Eine Niederlage im Monopol ist schwer zu schlucken, denn im Monopol geht es um Geld. Wenn Sie verlieren, müssen Sie den Rest der Spieler genau beobachten, wie sie das Spiel beenden, und Verluste sind in der Regel Swift und vernichtend. Daher werden die Regeln normalerweise irgendwann verdreht, um dem Eigeninteresse einiger Spieler auf Kosten der anderen zu dienen.

Sie spielen also Monopol mit Freunden wie Bob, Joe und Ed. Sie bauen schnell Ihr Imperium auf und verbrauchen Marktanteile mit einer exponentiellen Rate. Ihre Gegner werden schwächer und Sie beginnen (im übertragenen Sinne), Blut zu riechen. Ihr Kumpel Bob hat sein ganzes Geld darauf verwendet, so viele geringwertige Immobilien wie möglich zu verhaften, aber er erhält keinen hohen Return on Investment, wie er es erwartet hatte. Bob landet als Pechvogel auf Ihrem Boardwalk und wird aus dem Spiel verbannt.

Jetzt geht das Spiel vom freundlichen Würfeln zum ernsten Geschäft über. Bob wurde zum Beispiel für ein Versagen erklärt und Joe und Ed wollen nicht wie dieser Typ enden. Als führender Spieler werden Sie plötzlich zum Feind. Joe und Ed üben unter dem Tisch Trades, hinter dem Rücken Geldspritzen, unterbewerteten Haustausch und generell alles, was Sie als Spieler schwächen kann, bis einer von ihnen an die Spitze steigt.

Dann beginnt der Prozess von vorne, anstatt dass einer von ihnen gewinnt. Plötzlich wird ein endliches Regelwerk zu einem sich bewegenden Ziel und das Spiel degeneriert zu einer Art sozialer Interaktion, die die Grundlage jeder hochrangigen Reality-TV-Show seit Survivor bilden würde. Warum, weil sich die Regeln ändern und es keinen Konsens darüber gibt, wie/warum/was sie darstellen sollen, und, was noch wichtiger ist, es gibt niemanden, der die Entscheidungen trifft. Jeder Spieler im Spiel macht zu diesem Zeitpunkt seine eigenen Regeln und es kommt zu Chaos, bis zwei der Spieler zu müde sind, um die Scharade aufrechtzuerhalten und langsam aufzugeben.

Wenn also ein Regelbuch für ein Spiel genau einen Singleton darstellt, wäre das Monopolregelbuch ein Beispiel für Missbrauch.

Wie gilt das für die Programmierung?

Abgesehen von all den offensichtlichen Thread-Sicherheits- und Synchronisationsproblemen, die veränderliche Singletons mit sich bringen ... Wenn Sie einen Datensatz haben, der von mehreren verschiedenen Quellen gleichzeitig gelesen/manipuliert werden kann und während der Laufzeit der Anwendungsausführung besteht, Es ist wahrscheinlich eine gute Zeit, einen Schritt zurückzutreten und zu fragen, ob ich hier die richtige Datenstruktur verwende.

Persönlich habe ich gesehen, dass ein Programmierer einen Singleton missbraucht, indem er ihn als eine Art verdrehten Cross-Thread-Datenbankspeicher in einer Anwendung verwendet. Nachdem ich den Code direkt bearbeitet habe, kann ich bestätigen, dass er langsam war (wegen all der Thread-Sperren, die erforderlich waren, um ihn thread-sicher zu machen) und ein Albtraum war (wegen der unvorhersehbaren/sporadischen Natur von Synchronisationsfehlern) Unter Produktionsbedingungen kaum zu testen. Sicher, ein System hätte entwickelt werden können, das Polling/Signaling verwendet, um einige der Leistungsprobleme zu lösen, aber das würde die Probleme beim Testen nicht lösen und warum sollte es sich die Mühe machen, wenn eine "echte" Datenbank dieselbe Funktionalität bereits in einer viel robusteren Datenbank ausführen kann? skalierbare Weise.

Ein Singleton ist nur eine Option, wenn Sie benötigen, was ein Singleton bereitstellt. Eine schreibgeschützte schreibgeschützte Instanz eines Objekts. Dieselbe Regel sollte in Kaskade geschaltet werden auch die Eigenschaften/Mitglieder des Objekts.

31
Evan Plaice

Singleton handelt nicht von einer einzelnen Instanz!

Im Gegensatz zu anderen Antworten möchte ich nicht darüber sprechen, was mit Singletons falsch ist, sondern Ihnen zeigen, wie mächtig und beeindruckend sie sind, wenn sie richtig eingesetzt werden!

  • Problem : Singleton kann in Multithreading-Umgebungen eine Herausforderung sein
    Lösung : Verwenden Sie einen einzelnen Thread-Prozess bootstrap, um alle Abhängigkeiten Ihres Singleton zu initialisieren.
  • Problem : Es ist schwer, Singletons zu verspotten.
    Lösung : Verwenden Sie die Methode Factory zum Verspotten

Sie können die Klasse MyModel der Klasse TestMyModel zuordnen, die sie erbt, und zwar überall dort, wo MyModel injiziert wird und TestMyModel instread wird. - Problem : Singletons können Speicherlecks verursachen, da sie niemals entsorgt werden.
Lösung : Entsorgen Sie sie! Implementieren Sie einen Rückruf in Ihrer App, um Singletons ordnungsgemäß zu entsorgen. Entfernen Sie alle mit ihnen verknüpften Daten und schließlich: Entfernen Sie sie aus der Factory.

Wie ich beim Titel sagte, handelt es sich bei Singleton nicht um eine einzelne Instanz.

  • Singletons verbessern die Lesbarkeit : Sie können in Ihrer Klasse nachsehen, welcher Singleton injiziert wurde, um die Abhängigkeiten zu ermitteln.
  • Singletons verbessert die Wartung : Sobald Sie eine Abhängigkeit von einer Klasse entfernt haben, die Sie gerade mit einer Singleton-Injektion gelöscht haben, müssen Sie keinen großen Link von bearbeiten andere Klassen, die gerade Ihre Abhängigkeit verschoben haben (Dies ist stinkender Code für mich @ Jim Burger )
  • Singletons verbessern Speicher und Leistung : Wenn in Ihrer Anwendung etwas passiert und die Zustellung einer langen Kette von Rückrufen erforderlich ist, verschwenden Sie Speicher und Leistung. Durch die Verwendung von Singleton können Sie den Mittelmann ausschalten und die Leistung und Speichernutzung verbessern (indem Sie unnötige Zuweisungen lokaler Variablen vermeiden).
23
Ilya Gazman

Meine Antwort darauf, wie schlecht Singletons sind, lautet immer: "Es ist schwer, sie richtig zu machen." Viele der grundlegenden Komponenten von Sprachen sind Singletons (Klassen, Funktionen, Namespaces und sogar Operatoren) sowie Komponenten in anderen Aspekten der Datenverarbeitung (localhost, Standardroute, virtuelles Dateisystem usw.), und dies ist kein Zufall. Während sie von Zeit zu Zeit Ärger und Frustrationen verursachen, können sie auch dazu beitragen, dass viele Dinge VIEL besser funktionieren.

Die zwei größten Probleme, die ich sehe, sind: Es wie ein globales Problem behandeln und den Singleton-Verschluss nicht definieren.

Alle reden von Singleton's als Globalen, weil sie im Grunde genommen sind. Ein Großteil (leider nicht alle) der Bösartigkeit in einem globalen System hängt jedoch nicht von der Globalität ab, sondern davon, wie Sie es verwenden. Gleiches gilt für Singletons. Tatsächlich muss "einzelne Instanz" nicht unbedingt "global zugänglich" bedeuten. Es handelt sich eher um ein natürliches Nebenprodukt, und angesichts des schlechten Wissens sollten wir es nicht eilig haben, die globale Erreichbarkeit auszunutzen. Sobald Programmierer einen Singleton sehen, scheinen sie immer direkt über seine Instanzmethode darauf zuzugreifen. Stattdessen sollten Sie wie bei jedem anderen Objekt zu ihm navigieren. Der meiste Code sollte nicht einmal wissen, dass es sich um einen Singleton handelt (lose Kopplung, oder?). Wenn nur ein kleines Stück Code auf das Objekt zugreift, als wäre es ein globales Objekt, wird eine Menge Schaden rückgängig gemacht. Ich empfehle, dies durch Einschränkung des Zugriffs auf die Instanzfunktion zu erzwingen.

Der Singleton-Kontext ist ebenfalls sehr wichtig. Das bestimmende Merkmal eines Singleton ist, dass es "nur einen" gibt, aber in Wahrheit ist es "nur einen" in einer Art Kontext/Namespace. Es handelt sich normalerweise um eines pro Thread, Prozess, IP-Adresse oder Cluster, es kann sich aber auch um eines pro Prozessor, Computer, Sprachnamespace/Klassenladeprogramm/was auch immer, Subnetz, Internet usw. handeln.

Der andere, weniger verbreitete Fehler ist, den Singleton-Lebensstil zu ignorieren. Nur weil es nur einen einzigen gibt, heißt das nicht, dass ein Singleton allmächtig ist, "immer war und immer sein wird", und es ist auch nicht generell wünschenswert (Objekte ohne Anfang und Ende verletzen alle Arten nützlicher Annahmen im Code und sollten nur verwendet werden in den verzweifeltsten Umständen.

Wenn Sie diese Fehler vermeiden, können Singletons immer noch eine PITA sein, aber es ist bereit zu sehen, dass viele der schlimmsten Probleme erheblich gelindert werden. Stellen Sie sich einen Java Singleton vor, der explizit als einmal pro Klassenladeprogramm definiert ist (was bedeutet, dass er eine Thread-Sicherheitsrichtlinie benötigt), mit definierten Erstellungs- und Zerstörungsmethoden und einem Lebenszyklus, der vorschreibt, wann und wie sie aufgerufen werden, und Auf deren "Instanz" -Methode wird durch Paketschutz im Allgemeinen über andere, nicht globale Objekte zugegriffen. Immer noch eine potenzielle Problemquelle, aber sicherlich viel weniger.

Leider, anstatt gute Beispiele zu lehren, wie man Singletons macht. Wir bringen schlechte Beispiele bei, lassen Programmierer sie eine Weile verwenden und sagen ihnen dann, dass sie ein schlechtes Designmuster sind.

22

Siehe Wikipedia Singleton_pattern

Es wird auch von einigen Leuten als Antimuster angesehen, die der Meinung sind, dass es übermäßig verwendet wird, was unnötige Einschränkungen in Situationen mit sich bringt, in denen eine einzige Instanz einer Klasse tatsächlich nicht erforderlich ist. [1] [2] [3] [4]

Referenzen (nur relevante Referenzen aus dem Artikel)

  1. ^ Alex Miller. Muster, die ich hasse # 1: Singleton , Juli 2007
  2. ^ Scott Densmore. Warum Singletons böse sind , Mai 2004
  3. ^ Steve Yegge. Singletons als dumm angesehen , September 2004
  4. ^ J. B. Rainsberger, IBM. Benutze deine Singletons mit Bedacht , Juli 2001
21
GUI Junkie

Es ist nicht so, dass Singletons selbst schlecht sind, aber das GoF-Designmuster ist es. Das einzige wirklich gültige Argument ist, dass sich das GoF-Entwurfsmuster nicht für Tests eignet, insbesondere wenn Tests parallel ausgeführt werden.

Die Verwendung einer einzelnen Instanz einer Klasse ist ein gültiges Konstrukt, sofern Sie im Code die folgenden Mittel anwenden:

  1. Stellen Sie sicher, dass die Klasse, die als Singleton verwendet wird, eine Schnittstelle implementiert. Dies ermöglicht die Implementierung von Stubs oder Mocks über dieselbe Schnittstelle

  2. Stellen Sie sicher, dass der Singleton threadsicher ist. Das ist eine gegebene.

  3. Der Singleton sollte von Natur aus einfach und nicht übermäßig kompliziert sein.

  4. Verwenden Sie während der Laufzeit Ihrer Anwendung, in der Singletons an ein bestimmtes Objekt übergeben werden müssen, eine Klassenfactory, die dieses Objekt erstellt, und lassen Sie die Klassenfactory die Singleton-Instanz an die Klasse übergeben, die sie benötigt.

  5. Erstellen Sie während des Testens und um ein deterministisches Verhalten sicherzustellen, die Singleton-Klasse als separate Instanz, entweder als eigentliche Klasse oder als Stub/Mock, der ihr Verhalten implementiert, und übergeben Sie sie so, wie sie ist, an die Klasse, die sie benötigt. Verwenden Sie nicht den Klassenfaktor, der das zu testende Objekt erstellt, für das der Singleton während des Tests benötigt wird, da er die einzelne globale Instanz des Objekts übergibt, wodurch der Zweck zunichte gemacht wird.

Wir haben in unseren Lösungen mit großem Erfolg Singletons eingesetzt, die testbar sind und deterministisches Verhalten in parallelen Testläufen gewährleisten.

17
user1578119

Ich möchte die 4 Punkte in der akzeptierten Antwort ansprechen, hoffentlich kann jemand erklären, warum ich falsch liege.

  1. Warum ist es schlecht, Abhängigkeiten in Ihrem Code zu verstecken? Es gibt bereits Dutzende versteckter Abhängigkeiten (C-Laufzeitaufrufe, OS-API-Aufrufe, globale Funktionsaufrufe), und Singleton-Abhängigkeiten sind leicht zu finden (Suche nach instance ()).

    "Etwas global zu machen, um zu vermeiden, dass es weitergegeben wird, ist ein Codegeruch." Warum wird nicht etwas herumgereicht, um zu vermeiden, dass ein Singleton nach Code riecht?

    Wenn Sie ein Objekt durch 10 Funktionen in einem Aufrufstapel führen, nur um einen Singleton zu vermeiden, ist das dann so großartig?

  2. Grundsatz der Einzelverantwortung: Ich halte dies für etwas vage und hängt von Ihrer Definition der Verantwortung ab. Eine relevante Frage wäre, warum es wichtig ist, diese spezifische "Verantwortung" zu einer Klasse hinzuzufügen.

  3. Warum wird ein Objekt durch die Übergabe an eine Klasse enger gekoppelt, als wenn dieses Objekt als Singleton innerhalb der Klasse verwendet wird?

  4. Warum ändert sich, wie lange der Zustand dauert? Singletons können manuell erstellt oder zerstört werden, sodass das Steuerelement immer noch vorhanden ist. Sie können die Lebensdauer mit der Lebensdauer eines Nicht-Singleton-Objekts vergleichen.

In Bezug auf Unit-Tests:

  • nicht alle Klassen müssen einem Unit-Test unterzogen werden
  • nicht alle Klassen, die Unit-Tests unterzogen werden müssen, müssen die Implementierung des Singleton ändern
  • wenn sie do Unit-getestet werden müssen und die Implementierung ändern müssen, ist es einfach, eine Klasse von der Verwendung eines Singletons zur Übergabe des Singletons per Abhängigkeitsinjektion zu ändern.
16
Jon

Vince Huston hat diese Kriterien, die mir vernünftig erscheinen:

Singleton sollte nur in Betracht gezogen werden, wenn alle drei der folgenden Kriterien erfüllt sind:

  • Das Eigentum an der einzelnen Instanz kann nicht angemessen zugewiesen werden
  • Eine verzögerte Initialisierung ist wünschenswert
  • Ein globaler Zugriff ist nicht anderweitig vorgesehen

Wenn der Besitz der einzelnen Instanz, wann und wie die Initialisierung erfolgt und der globale Zugriff keine Rolle spielt, ist Singleton nicht interessant genug.

15
js.

Singletons sind aus puristischer Sicht schlecht.

Aus praktischer Sicht ist ein Singleton ein Kompromiss zwischen Entwicklungszeit und Komplexität .

Wenn Sie wissen, dass Ihre Anwendung sich nicht so stark ändert, sind sie in Ordnung. Wissen Sie nur, dass Sie möglicherweise Änderungen vornehmen müssen, wenn sich Ihre Anforderungen auf unerwartete Weise ändern (was in den meisten Fällen in Ordnung ist).

Singletons erschweren manchmal auch Komponententests .

14
tacone

An dem Muster ist von Natur aus nichts auszusetzen, vorausgesetzt, es wird für einen Aspekt Ihres Modells verwendet, der wirklich einzigartig ist.

Ich glaube, das Spiel ist auf die Überbeanspruchung zurückzuführen, die wiederum auf die Tatsache zurückzuführen ist, dass es das am einfachsten zu verstehende und umzusetzende Muster ist.

13
Ben Hoffstein

Ich werde das Gut/Böse-Argument nicht kommentieren, aber ich habe es nicht benutzt, seit Frühling mitgekommen ist. Die Verwendung von Abhängigkeitsinjektion hat meine Anforderungen an Singleton, Service-Locators und Fabriken so ziemlich aufgehoben. Ich finde das eine viel produktivere und sauberere Umgebung, zumindest für die Art der Arbeit, die ich mache (Java-basierte Webanwendungen).

13
prule

Singleton ist ein Muster und kann wie jedes andere Werkzeug verwendet oder missbraucht werden.

Der schlechte Teil eines Singletons ist im Allgemeinen der Benutzer (oder sollte ich die unangemessene Verwendung eines Singletons für Dinge sagen, für die es nicht entwickelt wurde). Der größte Täter benutzt einen Singleton als gefälschte globale Variable.

11
Martin York

Wenn Sie Code mit Singletons schreiben, beispielsweise mit einem Logger oder einer Datenbankverbindung, und anschließend feststellen, dass Sie mehr als ein Log oder mehr als eine Datenbank benötigen, treten Probleme auf.

Singletons erschweren es sehr, sich von ihnen zu normalen Objekten zu bewegen.

Es ist auch zu einfach, ein nicht threadsicheres Singleton zu schreiben.

Anstatt Singletons zu verwenden, sollten Sie alle benötigten Dienstprogrammobjekte von Funktion zu Funktion übergeben. Das kann vereinfacht werden, wenn Sie alle in ein Hilfsobjekt einbinden:

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

Neuester Artikel zu diesem Thema von Chris Reath unter Coding Without Comments .

Hinweis: Die Codierung ohne Kommentare ist nicht mehr gültig. Der Artikel, auf den verlinkt wird, wurde jedoch von einem anderen Benutzer geklont.

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

7
David

Das Problem mit Singletons ist das Problem des erweiterten Anwendungsbereichs und daher Kopplung . Es ist nicht zu leugnen, dass es einige Situationen gibt, in denen Sie Zugriff auf eine einzelne Instanz benötigen, und dies kann auf andere Weise erreicht werden.

Ich bevorzuge es jetzt, um einen Invertierung der Steuerung (IoC) -Container herum zu konstruieren und zu ermöglichen, dass die Lebensdauern durch den Container gesteuert werden. Dies gibt Ihnen den Vorteil, dass Klassen, die von der Instanz abhängen, nicht wissen, dass es eine einzelne Instanz gibt. Die Lebensdauer des Singleton kann in Zukunft geändert werden. Ein Beispiel, auf das ich kürzlich gestoßen bin, war eine einfache Anpassung von Single-Threaded zu Multi-Threaded.

FWIW, wenn es ein PIA ist, wenn Sie versuchen, es zu testen, dann geht es an PIA, wenn Sie versuchen, es zu debuggen, Fehler zu beheben oder zu verbessern.

7
Mark Lindell

Singletons sind NICHT schlecht. Es ist nur schlimm, wenn Sie etwas global Einzigartiges schaffen, das nicht global einzigartig ist.

Es gibt jedoch "Application Scope Services" (denken Sie an ein Messaging-System, das die Interaktion von Komponenten ermöglicht) - dies ist CALLS für einen Singleton, eine "MessageQueue" -Klasse mit der Methode "SendMessage (...)".

Sie können dann von überall Folgendes tun:

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

Und natürlich:

MessageQueue.Current.RegisterReceiver (this);

in Klassen, die IMessageReceiver implementieren.

7

Hier ist noch eine Sache über Singletons, die noch niemand gesagt hat.

In den meisten Fällen ist "Singletonität" eher ein Detail der Implementierung für eine Klasse als ein Merkmal ihrer Schnittstelle. Inversion von Control Container kann dieses Merkmal vor Klassenbenutzern verbergen. Sie müssen Ihre Klasse nur als Singleton markieren (zum Beispiel mit @Singleton Annotation in Java) und fertig. IoCC wird den Rest erledigen. Sie müssen keinen globalen Zugriff auf Ihre Singleton-Instanz bereitstellen, da der Zugriff bereits von IoCC verwaltet wird. Somit ist an IoC Singletons nichts auszusetzen.

GoF-Singletons sollen im Gegensatz zu IoC-Singletons "Singletonität" in der Schnittstelle durch die getInstance () -Methode offenlegen und unter allem leiden, was oben gesagt wurde.

6

Zu viele Leute setzen Objekte, die nicht threadsicher sind, in ein Singleton-Muster. Ich habe Beispiele für einen DataContext ( LINQ to SQL ) in einem Singleton-Muster gesehen, obwohl der DataContext nicht threadsicher ist und nur eine Arbeitseinheit darstellt.

6
Aaron Powell

Singletons sind nicht böse, wenn du es verwendest richtig & minimal. Es gibt viele andere gute Entwurfsmuster, die irgendwann die Anforderungen von Singleton ersetzen (und auch die besten Ergebnisse liefern). Aber einige Programmierer kennen diese guten Muster nicht und verwenden den Singleton für alle Fälle, die den Singleton für sie böse machen.

5
Sriram

Da es sich im Grunde genommen um objektorientierte globale Variablen handelt, können Sie Ihre Klassen normalerweise so gestalten, dass Sie sie nicht benötigen.

4
Ycros

Ein Muster entsteht, wenn mehrere Personen (oder Teams) zu ähnlichen oder identischen Lösungen gelangen. Viele Leute verwenden immer noch Singletons in ihrer ursprünglichen Form oder unter Verwendung von Factory-Vorlagen (gute Diskussion in Alexandrescus Modern C++ Design). Nebenläufigkeit und Schwierigkeiten bei der Verwaltung der Lebensdauer des Objekts sind die Haupthindernisse, wobei das erstere, wie Sie vorschlagen, einfach zu handhaben ist.

Singleton hat wie alle Möglichkeiten auch eine Menge Höhen und Tiefen zu bieten. Ich denke, sie können in Maßen verwendet werden, insbesondere für Objekte, die die Anwendungslebensdauer überstehen. Die Tatsache, dass sie Globalen ähneln (und wahrscheinlich sind), hat die Puristen vermutlich entmutigt.

4
user22044

Erstens sollten eine Klasse und ihre Mitarbeiter zunächst ihren beabsichtigten Zweck erfüllen, anstatt sich auf Deoendenten zu konzentrieren. Das Lebenszyklusmanagement (wenn Instanzen beschädigt werden und wenn sie den Geltungsbereich verlassen) sollte nicht Teil der Verantwortung der Clads sein. Die akzeptierte Best Practice hierfür ist das Erstellen oder Konfigurieren einer neuen Komponente zum Verwalten von Abhängigkeiten mithilfe der Abhängigkeitsinjektion.

Oft wird die Software komplizierter. Es ist sinnvoll, mehrere unabhängige Instanzen der Singleton-Klasse mit unterschiedlichem Status zu haben. In solchen Fällen ist es falsch, Code zu schreiben, um den Singleton einfach zu greifen. Die Verwendung von Singleton.getInstance() mag für kleine einfache Systeme in Ordnung sein, aber es funktioniert/skaliert nicht, wenn eine andere Instanz derselben Klasse benötigt wird.

Keine Klasse sollte als Singleton betrachtet werden, sondern als eine Anwendung ihrer Verwendung oder der Art und Weise, wie sie zum Konfigurieren von Abhängigen verwendet wird. Für einen schnellen und unangenehmen Fall spielt dies keine Rolle - nur die Hardcodierung sagt, dass Dateipfade keine Rolle spielen, aber für größere Anwendungen müssen solche Abhängigkeiten herausgerechnet und mit DI in geeigneterer Weise verwaltet werden.

Die Probleme, die Singleton beim Testen verursacht, sind ein Symptom für den hartcodierten Einzelnutzungsfall/die Umgebung. Die Testsuite und die vielen Tests sind jeweils individuell und unterscheiden sich voneinander, was mit der Hardcodierung eines Singleton nicht kompatibel ist.

4
mP.

Das Singleton - das Anti-Pattern! von Mark Radford (Overload Journal # 57 - Okt 2003) ist eine gute Lektüre darüber, warum Singleton als Anti-Pattern gilt. Der Artikel beschreibt auch zwei alternative Entwurfsansätze zum Ersetzen von Singleton.

3
Frank Grimm

Folgendes fehlt meiner Meinung nach in den bisherigen Antworten:

Wenn Sie eine Instanz dieses Objekts pro Prozessadressraum benötigen (und Sie sind sich sicher, dass sich diese Anforderung nicht ändert), sollten Sie es zu einem Singleton machen.

Ansonsten ist es kein Singleton.

Dies ist eine sehr merkwürdige Anforderung, die für den Benutzer kaum von Interesse ist. Prozesse und Adressraumisolation sind ein Implementierungsdetail. Sie wirken sich nur dann auf den Benutzer aus, wenn er Ihre Anwendung mit kill oder dem Task-Manager stoppen möchte.

Abgesehen vom Aufbau eines Caching-Systems gibt es nicht viele Gründe, warum Sie so sicher sein sollten, dass es nur eine Instanz von etwas pro Prozess geben sollte. Wie wäre es mit einem Protokollierungssystem? Wäre besser, wenn das pro Thread oder genauer wäre, damit Sie den Ursprung von Nachrichten automatischer verfolgen können. Wie wäre es mit dem Hauptfenster der Anwendung? Es hängt davon ab, ob; Vielleicht möchten Sie aus irgendeinem Grund, dass alle Dokumente des Benutzers durch denselben Prozess verwaltet werden. In diesem Fall würde es mehrere "Hauptfenster" in diesem Prozess geben.

3

Einige Kontrapunkte des Autors:

Sie stecken fest, wenn Sie die Klasse in Zukunft nicht mehr einzeln verwenden möchten Überhaupt nicht - Ich war in dieser Situation mit einem einzelnen Datenbankverbindungs-Singleton konfrontiert, den ich in einen Verbindungspool umwandeln wollte. Denken Sie daran, dass auf jeden Singleton über eine Standardmethode zugegriffen wird:

MyClass.instance

Dies ähnelt der Signatur einer Factory-Methode. Ich habe lediglich die Instanzmethode aktualisiert, um die nächste Verbindung aus dem Pool zurückzugeben - es sind keine weiteren Änderungen erforderlich. Das wäre viel schwieriger gewesen, wenn wir KEIN Singleton verwendet hätten.

Singletons sind nur ausgefallene Globals Kann nicht damit argumentieren, aber das sind alle statischen Felder und Methoden - alles, worauf von der Klasse zugegriffen wird, anstatt von einer Instanz, ist im Wesentlichen global und ich sehe nicht so viel Pushback auf die Verwendung statischer Felder?

Nicht zu sagen, dass Singletons gut sind, sondern nur einiges an "konventioneller Weisheit".

3
Ewan Makepeace

Es verwischt das Trennung von Bedenken .

Angenommen, Sie haben einen Singleton, können Sie diese Instanz von überall in Ihrer Klasse aufrufen. Ihre Klasse ist nicht mehr so ​​rein wie sie sein sollte. Ihre Klasse wird nun nicht mehr für ihre Mitglieder und die explizit empfangenen Mitglieder ausgeführt. Dies führt zu Verwirrung, da die Benutzer der Klasse nicht wissen, welche Informationen die Klasse benötigt. Die ganze Idee von Kapselung ist, das Wie einer Methode vor den Benutzern zu verbergen, aber wenn ein Singleton innerhalb der Methode verwendet wird, muss man den Zustand des Singleton kennen, um die Methode verwenden zu können korrekt. Das ist anti - OOP .

2
Graviton

Aus meinem Kopf:

  1. Sie erzwingen eine enge Kopplung. Wenn sich Ihr Singleton auf einer anderen Assembly befindet als sein Benutzer, kann die Using Assembly niemals funktionieren, ohne dass die Assembly den Singleton enthält.
  2. Sie ermöglichen zirkuläre Abhängigkeiten, z. B. kann Assembly A einen Singleton mit einer Abhängigkeit von Assembly B haben, und Assembly B kann den Singleton von Assembly A verwenden. Alles ohne den Compiler zu beschädigen.
1
Jon Limjap