Wie identifizieren wir, wann Abhängigkeitsinjektion oder Singleton-Muster verwendet werden sollen? Ich habe auf vielen Websites gelesen, dass dort "Abhängigkeitsinjektion über Singleton-Muster verwenden" steht. Aber ich bin mir nicht sicher, ob ich ihnen vollkommen zustimme. Für meine kleinen oder mittleren Projekte sehe ich die Verwendung von Singleton-Mustern definitiv unkompliziert.
Zum Beispiel Logger. Ich könnte verwenden. Logger.GetInstance().Log(...)
Aber warum muss ich stattdessen jede von mir erstellte Klasse mit der Instanz des Loggers injizieren?
quelle
Singletons sind wie Kommunismus: Beide klingen auf dem Papier großartig, explodieren aber in der Praxis vor Problemen.
Das Singleton-Muster legt einen unverhältnismäßigen Schwerpunkt auf den einfachen Zugriff auf Objekte. Der Kontext wird vollständig vermieden, da jeder Verbraucher ein Objekt mit AppDomain-Gültigkeitsbereich verwenden muss und keine Optionen für unterschiedliche Implementierungen übrig bleiben. Es bettet Infrastrukturwissen in Ihre Klassen ein (den Aufruf zu
GetInstance()
) und fügt gleichzeitig genau null Ausdruckskraft hinzu. Es verringert tatsächlich Ihre Ausdruckskraft, da Sie die von einer Klasse verwendete Implementierung nicht ändern können, ohne sie für alle zu ändern . Sie können einfach keine einmaligen Funktionen hinzufügen.Wenn die Klasse
Foo
davon abhängtLogger.GetInstance()
,Foo
werden ihre Abhängigkeiten effektiv vor den Verbrauchern verborgen. Dies bedeutet, dass Sie es nur dann vollständig verstehenFoo
oder verwenden können, wenn Sie die Quelle gelesen und die Tatsache aufgedeckt haben, dass es davon abhängtLogger
. Wenn Sie nicht über die Quelle verfügen, wird dadurch eingeschränkt, wie gut Sie den Code verstehen und effektiv verwenden können, von dem Sie abhängig sind.Das mit statischen Eigenschaften / Methoden implementierte Singleton-Muster ist kaum mehr als ein Hack zur Implementierung einer Infrastruktur. Es schränkt Sie auf vielfältige Weise ein und bietet keinen erkennbaren Nutzen gegenüber den Alternativen. Sie können es verwenden, wie Sie möchten, aber da es praktikable Alternativen gibt, die ein besseres Design fördern, sollte es niemals eine empfohlene Vorgehensweise sein.
quelle
Andere haben das Problem mit Singletons im Allgemeinen sehr gut erklärt. Ich möchte nur einen Hinweis zum speziellen Fall von Logger hinzufügen. Ich stimme Ihnen zu, dass es normalerweise kein Problem ist, als Singleton über eine statische Methode
getInstance()
oder einegetRootLogger()
Methode auf einen Logger (oder genauer gesagt auf den Root-Logger) zuzugreifen . (es sei denn, Sie möchten sehen, was von der Klasse, die Sie testen, protokolliert wird - aber meiner Erfahrung nach kann ich mich kaum an solche Fälle erinnern, in denen dies erforderlich war. Andererseits könnte dies für andere ein dringlicheres Problem sein).IMO ist normalerweise ein Singleton-Logger kein Problem, da er keinen Status enthält, der für die zu testende Klasse relevant ist. Das heißt, der Status des Loggers (und seine möglichen Änderungen) haben keinerlei Auswirkungen auf den Status der getesteten Klasse. Dies erschwert Ihre Unit-Tests nicht.
Die Alternative wäre, den Logger über den Konstruktor in (fast) jede einzelne Klasse in Ihrer App zu injizieren. Aus Gründen der Konsistenz der Schnittstellen sollte es auch dann eingefügt werden, wenn die betreffende Klasse derzeit nichts protokolliert. Die Alternative wäre, dass Sie, wenn Sie irgendwann feststellen, dass Sie jetzt etwas aus dieser Klasse protokollieren müssen, einen Logger benötigen Sie müssen einen Konstruktorparameter für DI hinzufügen, der den gesamten Clientcode bricht. Ich mag diese beiden Optionen nicht und ich bin der Meinung, dass die Verwendung von DI für die Protokollierung mein Leben nur komplizieren würde, um einer theoretischen Regel ohne konkreten Nutzen zu entsprechen.
Mein Fazit lautet also: Eine Klasse, die (fast) universell verwendet wird, aber keinen für Ihre App relevanten Status enthält, kann sicher als Singleton implementiert werden .
quelle
Es geht meistens, aber nicht vollständig um Tests. Singltons waren beliebt, weil es einfach war, sie zu konsumieren, aber Singletons haben eine Reihe von Nachteilen.
DI bietet Ihnen den einfachen Verbrauch Ihrer abhängigen Klassen - geben Sie es einfach in die Konstruktorargumente ein, und das System stellt es für Sie bereit - und bietet Ihnen gleichzeitig die Flexibilität beim Testen und Konstruieren.
quelle
Das einzige Mal, dass Sie jemals einen Singleton anstelle von Dependency Injection verwenden sollten, ist, wenn der Singleton einen unveränderlichen Wert darstellt, wie z. B. List.Empty oder dergleichen (unter der Annahme unveränderlicher Listen).
Die Darmprüfung für einen Singleton sollte lauten: "Wäre ich in Ordnung, wenn dies eine globale Variable anstelle eines Singleton wäre?" Wenn nicht, verwenden Sie das Singleton-Muster, um eine globale Variable zu dokumentieren, und sollten einen anderen Ansatz in Betracht ziehen.
quelle
Ich habe gerade den Monostate-Artikel gelesen - es ist eine raffinierte Alternative zu Singleton, aber es hat einige seltsame Eigenschaften:
Ist das nicht beängstigend - weil der Mapper wirklich von der Datenbankverbindung abhängig ist, um save () auszuführen -, aber wenn zuvor ein anderer Mapper erstellt wurde, kann er diesen Schritt beim Erfassen seiner Abhängigkeiten überspringen. Es ist zwar ordentlich, aber auch etwas chaotisch, nicht wahr?
quelle
Es gibt andere Alternativen zu Singleton: Proxy- und MonoState-Muster.
http://www.objectmentor.com/resources/articles/SingletonAndMonostate.pdf
Wie kann das Proxy-Muster verwendet werden, um einen Singleton zu ersetzen?
quelle