Ist es eine schlechte Idee, eine Klasse zu erstellen, die nur eine Instanz hat?

9

Ist es eine schlechte Codierungspraxis / -gestaltung, eine Klasse zu erstellen, die nur einmal instanziiert wird?

Ich habe einige Variablen und Funktionen, die unter einer Klasse zusammengefasst werden können, um "gut auszusehen" (mangels einer besseren Beschreibung), da sie etwas verwandt sind, aber sie können nur globale Variablen und globale Funktionen sein.

(Übrigens verwende ich JavaScript, AngularJS, Express, MongoDB.)

Alice
quelle
2
Vielleicht brauchen Sie eine Singleton-Klasse. Es ist jedoch eine schlechte Idee, in einer Klasse Dinge zu binden, die nicht richtig zusammenhängen.
NeonGlow
2
Singleton-Muster ist schlecht. Eine einzelne Instanz ist manchmal die richtige Lösung.
Bryan Chen
4
Weder "Singleton" noch "Einzelinstanz" sind eine gute Lösung, um "nur etwas verwandte" globale Dinge zusammenzufassen - wenn ich eine solche Beschreibung höre, nehme ich dies immer als Warnsignal. Um Ihnen eine ernsthafte Antwort zu geben, sollten Sie uns einige Beispiele für die Variablen und Funktionen nennen, die Sie zusammenfassen möchten (mit ihren tatsächlichen Namen und ihrer Bedeutung).
Doc Brown
2
Das Singleton-Muster ist nicht unbedingt schlecht. Es ist nur so, dass es dazu neigt, überbeansprucht zu werden.
Stephen
Ist es überhaupt technisch möglich, einen Singleton in JavaScript zu erzwingen?
Amy Blankenship

Antworten:

10

Eine einzelne Instanz für eine Klasse ist sinnvoll, wenn das Objekt eine einzelne Ressource darstellt, z. B. eine Ethernet-Verbindung oder den Task-Manager des Betriebssystems.

Funktionen werden nur dann in eine Klasse eingefügt, wenn sie auf die Variablen von Instanzen dieser Klasse einwirken. Andernfalls ist der Betreuer über die Absicht dieser Klasse verwirrt.

Normalerweise gibt es einen guten Grund, warum Ihre App globale Variablen enthält. Versuchen Sie, den gemeinsamen Zweck von ihnen zu finden und eine Klasse um diesen Zweck herum zu entwerfen. Es wird nicht nur das Design klar machen, sondern auch Ihren Verstand.

Mouviciel
quelle
2
+1, aber ich möchte hinzufügen: „Wenn der einzige gemeinsame Ziel ist es, dass diese Variablen sind global, besser lassen sie in verschiedenen Klassen.“
Doc Brown
13

Es ist kein Problem, eine Klasse zu schreiben, die nur einmal instanziiert wird.

Wenn das Zusammenfügen einiger Variablen und Funktionen innerhalb einer Klasse sinnvoll ist, einen semantischen Wert hat oder das Lesen und Bearbeiten des Codes vereinfacht, sind die Betreuer dankbar.

Was jedoch sehr falsch sein kann, ist die Durchsetzung der Einzigartigkeit von innen heraus.

Viele Leute neigen dazu, das Singleton-Muster abzufeuern, sobald sie denken, dass sie nur eine Instanz von etwas benötigen. Sehen Sie zum Beispiel, wie Sie Ihren Kontext nicht ausführlich beschrieben haben, aber die meisten Antworten schlagen bereits vor, einen Singleton zu verwenden. Und dann könnte das Design durcheinander geraten, denn wenn Sie aus irgendeinem Grund irgendwann eine andere Instanz benötigen, verhindert die Klasse, dass Sie dies tun, ohne viel Code zu ändern.

Als Fazit ist eine Instanz in Ordnung, aber stellen Sie sicher, dass Sie wissen, ob:

  1. Sie benötigen nur eine Instanz oder
  2. Sie können nicht mehr als eine Instanz haben (ein sehr, sehr seltener Fall meiner Erfahrung nach).
Julien Guertault
quelle
1
Betreff: # 2, ich glaube nicht, dass dies jemals gültig ist. Selbst wenn Ihr Objekt ein NuclearPowerStationCentralCommandController ist und Sie immer nur ein Kernkraftwerk besitzen, sagen Sie mir nicht ernsthaft, dass Sie keinen MockNuclearPowerStationCentralCommandController zum Testen haben, oder?
Phoshi
Ein schwerwiegenderes, aber weniger offensichtliches Problem ist, wenn Sie eine etwas andere Implementierung des Singleton benötigen, dies in den meisten Sprachen nicht möglich ist, da Sie den Singleton direkt erhalten, anstatt die Instanz übergeben zu lassen .
Amy Blankenship
@Phoshi: Wenn nur eines von etwas jemals existieren kann, kann Code es verwenden, ohne eine Referenz enthalten zu müssen. Wenn mehrere Instanzen vorhanden sein dürfen, müssen Verbraucher Verweise darauf haben. Dies erhöht nicht nur die Speicheranforderung des Objekts, sondern die Verbraucher können auch nicht mehr davon ausgehen, dass andere Verbraucher einen Verweis auf dasselbe Objekt haben. Dies erhöht die Komplexität erheblich. Wenn die Komplexität notwendig wird, ist es besser, sie eher früher als später hinzuzufügen, aber wenn sie nicht notwendig ist, kann sie am besten vermieden werden.
Supercat
@supercat: Das Hinzufügen der Speichernutzung einer Referenz ist für die überwiegende Mehrheit der Fälle völlig irrelevant. Ich denke, das ist überhaupt kein guter Grund, DI zu vermeiden. Sie haben Recht, dass Sie nicht mehr davon ausgehen können, dass jeder dieselbe Instanz hat - Sie sollten nicht, das sollte keine Rolle spielen. Es spielt keine Rolle, ob jeder eine andere Instanz hat, solange die Semantik der Schnittstelle gilt. Wie ich schon sagte, Sie werden nie nur eine Instanz haben. Sie haben noch mindestens eine zum Testen und möchten wirklich die Annahme riskieren, dass sich Ihre Anforderungen nie ändern werden?
Phoshi
@Phoshi: Die Speichernutzung ist nicht das Problem; Das Problem ist, dass man eine andere Art hinzufügt, in der sich Objekte unterscheiden können. Stellen Sie sich zum Beispiel vor, was es bedeutet, dass die Elemente in zwei Fällen Dictionary<TKey,KTValue>unterschiedlich sind. Wenn alle Instanzen einer Dictionary<TKey,KTValue>Instanz dasselbe verwenden IEqualityComparer, gibt es keine Mehrdeutigkeit, aber wenn sie unterschiedliche Komparatoren verwenden können, die unterschiedliche Äquivalenzbeziehungen definieren, weiß ich nicht, dass es sinnvoll ist, sinnvoll zu definieren, a.ContentsDistinctFrom(b)um immer gleich zu sein b.ContentsDistinctFrom(a).
Supercat
3

Ist es eine schlechte Codierungspraxis / -gestaltung, eine Klasse zu erstellen, die nur einmal instanziiert wird?

Nein, auch wenn Sie nur einmal instanziiert haben, benötigen Sie eine Klasse dafür. Aber nehmen Sie nicht an, dass Sie jetzt und in Zukunft immer nur eine Instanz benötigen.

Angenommen, Sie machen ein Spiel und haben eine Spielerklasse:

class Player {
    ...
}

Sie werden eine Spielerklasse in Ihrem Spiel instanziieren und immer das gleiche Objekt verwenden. Daran ist nichts auszusetzen.

Machen Sie jedoch keinen Singleton daraus! Heute gestaltest du dein Spiel und denkst: "Nun, es wird immer ein Einspieler-Spiel sein. Ich werde einen Singleton für meinen Spieler verwenden." In Version 2 möchten Sie möglicherweise den Mehrspielermodus implementieren - und dann geraten Sie in Schwierigkeiten. Sie müssen viel Code neu schreiben und anpassen, da Ihr Design das Instanziieren mehrerer Player nicht unterstützt.

Das gleiche gilt für Caches. Oder Logger. Oder Netzwerkschnittstellen. Heute denken Sie, dass Sie mit Sicherheit immer nur einen brauchen werden. In einer zukünftigen Version müssen Sie jedoch eine Sekunde hinzufügen. Seien Sie sich dieser Situation bewusst.

Uooo
quelle
1

Es gibt Singleton-Klassen, und das ist ein gängiges Entwurfsmuster.

Es gibt auch Klassen, die niemals instanziiert werden. Wenn Sie Funktionen haben, die NICHT in einem dauerhaften Zustand arbeiten (z. B. nehmen sie die Eingabe und transformieren sie), können Sie normalerweise eine statische Methode verwenden. In einigen Sprachen (wie Java) werden diese statischen Methoden in einer Klasse deklariert, aber die Klasse selbst wird niemals instanziiert.

Uri
quelle
1

Das Singleton-Muster ist üblich. Sie können damit eine einzelne Instanz einer Klasse erzwingen.

Aber für einige ist es zu häufig, so dass es ein Anti-Muster wird. Der Grund dafür ist, dass es praktisch dasselbe ist wie der globale Staat. Und jeder globale Staat ist schwer zu verspotten und zu testen und schwer zu debuggen. Gleichzeitig kann das explizite Übergeben dieser einen Instanz überall in Ihrem Code dazu führen, dass sich der Code stark aufbläht. Aber das wird Sie über die richtige Architektur nachdenken lassen. Wenn eine Reihe von Klassen diesen einen Singleton verwenden, können Sie feststellen, dass sie irgendwie miteinander verwandt sind, und einen gemeinsamen Vorfahren für sie erstellen, der diese eine Instanz für sie kapselt.

Euphorisch
quelle
1

Es ist schlecht anzunehmen, dass etwas allgemein schlecht ist. In Ihrem Fall wäre es vielleicht eine gute Idee, aber da Sie eine Sprache verwenden, die im Kern nicht OO ist, ist es wahrscheinlich besser, nur lose Methoden und Variablen zu verwenden und sie in eine gemeinsame Bibliothek zu stellen, die Sie in Ihre Bibliothek aufnehmen andere Arbeit.

jwenting
quelle
1

Sie stellen zwei Fragen in einer.

  1. Nein, es ist nichts Schlimmes, eine Klasse zu haben, die nur eine Instanz hat.
  2. Das Gruppieren von Variablen und Methoden in einer Klasse ohne wirklichen Grund ist ein schlechtes Design.
Tulains Córdova
quelle