2148 Stimmen

Was sind die Nachteile des Singleton-Musters?

El Singleton-Muster ist ein voll eingezahltes Mitglied der GoF 's Musterbuch aber in letzter Zeit scheint sie in der Welt der Entwickler eher verwaist zu sein. Ich verwende immer noch eine ganze Menge Singletons, vor allem für Fabrikklassen und obwohl man bei Multithreading-Problemen etwas vorsichtig sein muss (wie bei jeder anderen Klasse auch), verstehe ich nicht, warum sie so schrecklich sind.

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

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

36voto

Ilya Gazman Punkte 29734

Bei Singleton geht es nicht um eine einzige Instanz!

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

  • Problem : Singleton kann in einer Multithreading-Umgebung eine Herausforderung sein
    Lösung : Verwenden Sie einen Single-Threaded-Bootstrap-Prozess, um alle Abhängigkeiten Ihres Singletons zu initialisieren.
  • Problem : Es ist schwer, sich über Singles lustig zu machen.
    Lösung : Methode verwenden Fabrik Muster für Spotting

Sie können Folgendes abbilden MyModel à TestMyModel Klasse, die sie erbt, überall, wenn MyModel injiziert wird, erhalten Sie TestMyModel einlesen. - Problem : Singletons können Speicherlecks verursachen, da sie nie entsorgt werden.
Lösung : Nun, entsorgen Sie sie! Implementieren Sie einen Callback 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 bereits im Titel erwähnt habe, geht es bei Singleton nicht um eine einzelne Instanz.

  • Singletons verbessern die Lesbarkeit : Sie können sich Ihre Klasse ansehen und sehen, welches Singleton sie injiziert hat, um herauszufinden, welche Abhängigkeiten sie hat.
  • Singletons verbessert die Wartung : Sobald Sie eine Abhängigkeit von einer Klasse entfernt haben, haben Sie nur eine Singleton-Injektion gelöscht, Sie müssen nicht gehen und einen großen Link von anderen Klassen bearbeiten, die nur Ihre Abhängigkeit verschoben haben (Das ist stinkender Code für mich @Jim Burger )
  • Singletons verbessert Gedächtnis und Leistung : Wenn etwas in Ihrer Anwendung passiert, und es dauert eine lange Kette von Rückrufen zu liefern, Sie verschwenden Speicher und Leistung, durch die Verwendung von Singleton Sie schneiden den mittleren Mann, und verbessern Sie Ihre Leistung und Speichernutzung (durch die Vermeidung von unnötigen lokalen Variablen Zuweisungen).

36voto

Evan Plaice Punkte 13682

Monopole sind der Teufel und Singletons mit nicht-lesbarem/veränderbarem Status sind das "wahre" Problem...

Nach der Lektüre Singletons sind pathologische Lügner wie vorgeschlagen in Jasons Antwort Ich bin auf diesen kleinen Leckerbissen gestoßen, der das am besten dargestellte Beispiel für wie Singletons werden oft missbraucht.

Global ist schlecht, weil:

  • a. Es verursacht Namensraumkonflikte
  • b. Sie stellt den Staat in ungerechtfertigter Weise bloß

Wenn es um Singletons geht

  • a. Der explizite OO-Aufruf verhindert die Konflikte, so dass Punkt a. kein Problem darstellt.
  • b. Singletons ohne Zustand (wie Fabriken) stellen kein Problem dar. Singletons mit Zustand können wiederum in zwei Kategorien fallen, diejenigen, die unveränderlich sind oder einmal schreiben und viele lesen (Konfigurations-/Eigenschaftsdateien). Diese sind nicht schlecht. Mutable Singletons, die eine Art von Referenzhalter sind, sind diejenigen, von denen Sie sprechen.

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

Was bedeutet das für Monopoly?

Um ein Monopoly-Spiel zu beginnen, müssen Sie zuerst:

  • wir legen zuerst die Regeln fest, damit alle auf der gleichen Seite sind
  • Jeder erhält zu Beginn des Spiels die gleichen Startbedingungen.
  • um Verwirrung zu vermeiden, wird nur ein Satz von Regeln vorgelegt
  • die Regeln dürfen sich während des Spiels nicht ändern

Für alle, die es noch nicht wissen wirklich Monopol gespielt haben, sind diese Standards bestenfalls ideal. Eine Niederlage bei Monopoly ist schwer zu schlucken, denn bei Monopoly geht es um Geld, und wenn man verliert, muss man mühsam zusehen, wie der Rest der Spieler das Spiel beendet, und die Verluste sind in der Regel schnell und vernichtend. Also werden die Regeln irgendwann so verdreht, dass sie den Eigeninteressen einiger Spieler auf Kosten der anderen dienen.

Du spielst also Monopoly mit deinen Freunden Bob, Joe und Ed. Sie bauen Ihr Imperium rasch aus und erobern sich exponentiell Marktanteile. Ihre Gegner werden schwächer und Sie beginnen, Blut zu riechen (im übertragenen Sinne). Ihr Kumpel Bob hat sein ganzes Geld in das Gridlocking von möglichst vielen Immobilien mit geringem Wert gesteckt, aber seine Rendite ist nicht so hoch, wie er erwartet hatte. Bob hat das Pech, dass er auf Ihrem Boardwalk landet und aus dem Spiel genommen wird.

Jetzt wird das Spiel vom freundschaftlichen Würfeln zur ernsten Angelegenheit. Bob wurde als Beispiel für einen Versager hingestellt, und Joe und Ed wollen nicht wie "dieser Typ" enden. Als führender Spieler wird man also plötzlich zum Feind. Joe und Ed fangen an, unter dem Tisch zu handeln, hinter dem Rücken Geld zuzuschießen, unterbewertete Häuser zu tauschen und generell alles zu tun, um dich als Spieler zu schwächen, bis einer von ihnen an die Spitze kommt.

Wenn dann nicht einer von ihnen gewinnt, beginnt der Prozess von vorne. Plötzlich wird ein begrenztes Regelwerk zu einem beweglichen Ziel und das Spiel verkommt zu einer Art von sozialer Interaktion, die die Grundlage jeder hochkarätigen Reality-TV-Show seit Survivor bildet. Der Grund dafür ist, dass sich die Regeln ändern und es keinen Konsens darüber gibt, wie/warum/was sie repräsentieren sollen, und - was noch wichtiger ist - es gibt keine Person, die die Entscheidungen trifft. Jeder Spieler macht zu diesem Zeitpunkt seine eigenen Regeln und das Chaos nimmt seinen Lauf, bis zwei der Spieler zu müde sind, um die Scharade aufrechtzuerhalten und langsam aufgeben.

Wenn also ein Spielregelwerk ein Singleton korrekt darstellt, wäre das Monopoly-Regelwerk ein Beispiel für Missbrauch.

Was bedeutet das für die Programmierung?

Abgesehen von den offensichtlichen Problemen mit der Thread-Sicherheit und Synchronisation, die veränderbare Singletons mit sich bringen... Wenn Sie einen Datensatz haben, der von mehreren verschiedenen Quellen gleichzeitig gelesen/manipuliert werden kann und während der gesamten Dauer der Anwendungsausführung existiert, ist es wahrscheinlich an der Zeit, einen Schritt zurückzutreten und sich zu fragen: "Verwende ich hier den richtigen Typ von Datenstruktur".

Ich persönlich habe gesehen, wie ein Programmierer ein Singleton missbraucht hat, indem er es als eine Art verdrehten, Thread-übergreifenden Datenbankspeicher innerhalb einer Anwendung verwendet hat. Nachdem ich direkt an dem Code gearbeitet habe, kann ich bestätigen, dass er langsam war (wegen all der Thread-Sperren, die benötigt werden, um ihn thread-sicher zu machen) und ein Alptraum bei der Arbeit (wegen der unvorhersehbaren/intermittierenden Natur von Synchronisationsfehlern), und fast unmöglich unter "Produktionsbedingungen" zu testen. Sicherlich hätte man ein System mit Polling/Signaling entwickeln können, um einige der Leistungsprobleme zu überwinden, aber das würde die Probleme beim Testen nicht lösen, und warum sollte man sich die Mühe machen, wenn eine "echte" Datenbank dieselbe Funktionalität bereits auf eine viel robustere/skalierbarere Weise erfüllen kann.

Ein Singleton ist sólo eine Option, wenn Sie benötigen, was ein Singleton bietet. Eine schreibgeschützte Nur-Lese-Instanz eines Objekts. Diese Regel sollte auch auf die Eigenschaften/Mitglieder des Objekts übertragen werden.

25voto

Christopher Smith Punkte 5151

Meine Antwort auf die Frage, warum Singletons schlecht sind, lautet immer: "Sie sind schwer richtig zu machen". Viele der grundlegenden Komponenten von Sprachen sind Singletons (Klassen, Funktionen, Namespaces und sogar Operatoren), ebenso wie Komponenten in anderen Bereichen der Datenverarbeitung (localhost, Standardroute, virtuelles Dateisystem usw.), und das ist kein Zufall. Sie verursachen zwar gelegentlich Ärger und Frustration, können aber auch dafür sorgen, dass viele Dinge viel besser funktionieren.

Die beiden größten Fehler, die ich sehe, sind: die Behandlung wie eine globale und nicht zu definieren, die Singleton Schließung.

Alle reden von Singletons als Globals, weil sie das im Grunde auch sind. Jedoch viel (leider nicht alle) der Schlechtigkeit in einem globalen kommt nicht intrinsisch von global, aber wie Sie es verwenden. Dasselbe gilt für Singletons. Sogar noch mehr, da "einzelne Instanz" wirklich nicht "global zugänglich" bedeuten muss. Es ist eher ein natürliches Nebenprodukt, und in Anbetracht all des Schlechten, das wir kennen, sollten wir es nicht so eilig haben, die globale Zugänglichkeit zu nutzen. Sobald Programmierer ein Singleton sehen, scheinen sie es immer direkt über seine Instanzmethode anzusprechen. Stattdessen sollte man es wie jedes andere Objekt ansteuern. Der meiste Code sollte sich nicht einmal bewusst sein, dass er es mit einem Singleton zu tun hat (lose Kopplung, richtig?). Wenn nur ein kleiner Teil des Codes auf das Objekt zugreift, als wäre es ein globales Objekt, wird eine Menge Schaden angerichtet. Ich empfehle, dies zu erzwingen, indem der Zugriff auf die Instanzfunktion eingeschränkt wird.

Der Singleton-Kontext ist ebenfalls sehr wichtig. Das definierende Merkmal eines Singletons ist, dass es "nur eines" gibt, aber in Wahrheit ist es "nur eines" innerhalb einer Art von Kontext/Namensraum. In der Regel handelt es sich um eines pro Thread, Prozess, IP-Adresse oder Cluster, aber auch um eines pro Prozessor, Maschine, Sprach-Namensraum/Klassenlader/was auch immer, Subnetz, Internet usw.

Der andere, weniger verbreitete Fehler besteht darin, den Singleton-Lebensstil zu ignorieren. Nur weil es nur ein Singleton gibt, heißt das nicht, dass ein Singleton ein allmächtiges "das war schon immer so und wird auch immer so sein" ist, und es ist auch nicht generell wünschenswert (Objekte ohne Anfang und Ende verletzen alle möglichen nützlichen Annahmen im Code und sollten nur unter den verzweifeltsten Umständen eingesetzt werden.

Wenn man diese Fehler vermeidet, können Singletons zwar immer noch ein Ärgernis sein, aber viele der schlimmsten Probleme werden dadurch deutlich gemildert. Stellen Sie sich ein Java-Singleton vor, das explizit als einmal pro Classloader definiert ist (was bedeutet, dass es eine Thread-Safety-Policy braucht), mit definierten Erstellungs- und Zerstörungsmethoden und einem Lebenszyklus, der vorschreibt, wann und wie sie aufgerufen werden, und dessen "Instanz"-Methode einen Paketschutz hat, so dass auf sie im Allgemeinen über andere, nicht-globale Objekte zugegriffen wird. Dies ist zwar immer noch eine potenzielle Problemquelle, aber sicherlich viel weniger problematisch.

Leider lehren wir keine guten Beispiele, wie man Singletons macht. Wir lehren schlechte Beispiele, lassen die Programmierer eine Zeit lang damit herumlaufen und sagen ihnen dann, dass sie ein schlechtes Entwurfsmuster sind.

25voto

GUI Junkie Punkte 519

Siehe Wikipedia Singleton_pattern

Es wird von einigen auch als Anti-Pattern betrachtet, da es ihrer Meinung nach übermäßig genutzt wird und unnötige Einschränkungen in Situationen einführt, in denen eine einzige Instanz einer Klasse eigentlich 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 Singles böse sind Mai 2004
  3. ^ Steve Yegge. Singles gelten als dumm September 2004
  4. ^ J.B. Rainsberger, IBM. Setzen Sie Ihre Singletons klug ein Juli 2001

18voto

Es ist nicht so, dass Singletons an sich schlecht sind, aber das GoF-Designmuster ist es. Das einzige wirklich stichhaltige Argument ist, dass sich das GoF-Entwurfsmuster nicht für Tests eignet, vor allem wenn diese parallel ausgeführt werden.

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

  1. Stellen Sie sicher, dass die Klasse, die als Singleton verwendet werden soll, eine Schnittstelle implementiert. Dadurch können Stubs oder Mocks mit der gleichen Schnittstelle implementiert werden

  2. Stellen Sie sicher, dass das Singleton thread-sicher ist. Das ist eine Selbstverständlichkeit.

  3. Das Singleton sollte einfach und nicht übermäßig kompliziert sein.

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

  5. Während des Testens und um ein deterministisches Verhalten zu gewährleisten, erstellen Sie die Singleton-Klasse als separate Instanz, entweder als die eigentliche Klasse selbst oder als Stub/Mock, der ihr Verhalten implementiert, und übergeben Sie sie unverändert an die Klasse, die sie benötigt. Verwenden Sie nicht den Klassenfaktor, der das zu testende Objekt erzeugt, das die Singleton-Klasse während des Tests benötigt, da er die einzelne globale Instanz der Klasse übergibt, was den Zweck verfehlt.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X