Mir ist klar, dass es viele Diskussionen über Singletons gibt und warum das schlecht ist. Darum geht es in dieser Frage nicht. Ich verstehe die Nachteile von Singletons.
Ich habe ein Szenario, in dem die Verwendung eines Singletons einfach ist und sinnvoll erscheint. Ich möchte jedoch eine Alternative, die das erreicht, was ich brauche, ohne viel Overhead.
Unsere Anwendung ist als Client konzipiert, der in der Regel auf Laptops vor Ort ausgeführt wird und mit einem Back-End-Server kommuniziert. Wir haben eine Statusleiste am unteren Rand der Hauptanwendung. Es enthält einige Textbereiche, die verschiedene Statuen und Informationen sowie verschiedene Symbole zeigen. Die Symbole ändern ihr Bild, um ihren Status anzuzeigen. Wie ein GPS-Symbol, das anzeigt, ob es angeschlossen ist oder nicht, sowie Fehlerstatus.
Unsere Hauptklasse heißt MobileMain. Es besitzt den Bereich der Statusleiste und ist für die Erstellung zuständig. Wir haben dann eine StatusBarManager-Klasse. Der StatusBarManager ist derzeit eine statische Klasse, könnte aber auch ein Singleton sein. Hier ist der Beginn der Klasse.
%Vor%Der MobileMain fragt den StatusBarManager nach einer Statusleiste. Es verwendet dann die Statusleiste. Keine anderen Klassen sehen die StatusBar, nur den StatusBarManager.
Aktualisierungen an der Statusleiste können von fast überall in der Anwendung kommen. Es gibt ungefähr 20 Klassen, die die Textbereiche in der Statusleiste und zusätzliche Klassen aktualisieren können, die die Symbolzustände aktualisieren.
Es wird nur jeweils eine StatusBar und einen StatusBarManager geben.
Irgendwelche Vorschläge für eine bessere Umsetzung?
Einige Gedanken, die ich hatte:
Machen Sie den StatusBarManager zu einer Instanzklasse. Behalten Sie in meiner MobileMain-Klasse eine statische öffentliche Instanz der StatusBarManager-Klasse. Dann würden Sie zur Aktualisierung der Statusleiste MobileMain.StatusBarManager.SetInformationText oder eine andere Methode des Managers aufrufen. Der StatusBarManager wäre kein Singleton, sondern der MobileMain würde nur eine statische Instanz davon erstellen. Das Problem hierbei ist, dass MobileMain jetzt eine StatusBar und einen StatusBarManager besitzt, der nur die StatusBar verwaltet, die ihm gehört. Immer noch eine global verfügbare statische Instanz für den StatusBarManager, nur ein anderer Besitzer.
Eine andere Idee war, etwas wie eine EventEgregator-Klasse zu verwenden. Ich habe noch nie eines benutzt, aber ich habe über sie gelesen. Ich denke, das Konzept ist, dass es eine global verfügbare Klasse wäre. In jeder Klasse, die die Statusleiste aktualisieren möchte, wird ein StatusBarUpdate-Ereignis veröffentlicht. Der StatusBarManager ist die einzige Klasse, die das StatusBarUpdate-Ereignis abonniert und alle Benachrichtigungen erhält. Ich habe jedoch gelesen, dass dies zu Undichtigkeiten führen kann, wenn Sie sich nicht damit abmühen, Ereignisse von Objekten zu entfernen. Ist dieser Ansatz lohnenswert?
Es ist keine große Sache, eine StatusBar-Klasse oder eine StatusBarManager-Klasse zu haben. Aber viele Klassen in Ihrer App wissen über StatusBars und StatusBarManagers zu wissen, ist eine schlechte Idee, wird es starke Kopplung verursachen, und eines Tages wahrscheinlich Schmerzen.
Wie?
Stellen Sie sich vor, dass die Komponenten, die derzeit den Status einer Statusleiste melden, in einer anderen App wiederverwendet werden müssen - verwendet eine Textkonsole, um den Status zu melden? - meldet den Status an mehrere Orte? oder - meldet überhaupt keinen Status!
Beste Alternative: -Event hören. Zeigen Sie ein Statusänderungsereignis für Ihre Klasse an (Sie können einen Rückruf verwenden) oder vielleicht für eine vorhandene freigegebene Ressource, die Ihre Klassen gemeinsam haben. Andere Parteien, wie Ihre Statusleiste, können die Veranstaltung abonnieren. Und sollten Sie sich abmelden, wenn das Abonnement nicht mehr benötigt / gültig ist, um Lecks zu vermeiden, wie Sie erwähnen!
- Da Sie WPF für WPF mit einer Abhängigkeitseigenschaft 'StatusText' markiert haben, scheint dies eine weitere verlockende Option zu sein. Bei dieser Vorgehensweise müssen Sie bei mehreren Statuseigenschaften herausfinden, welche davon angezeigt wird Sie haben den interessantesten Status, der jetzt in Ihrer Statusleiste angezeigt werden muss! Dies könnte ein bindender, multibinding (blech, Komplexität) oder abhängigkeitseigener Event-Handler sein.
Allerdings würde ich Ihnen empfehlen, DependencyObjects und DependencyProperties so weit wie möglich auf Ihre UI-Ebene beschränkt zu lassen. Der Grund dafür ist, dass sie sich implizit auf einen Dispatcher im Benutzeroberflächenthread verlassen und daher für Nicht-UI-Aufgaben nicht einfach angepasst werden können.
Da es viele verschiedene Teile Ihrer App gibt, können Sie möglicherweise auch eine Kombination aus beiden finden, indem Sie einen Ort und einen anderen verwenden.
Ich bevorzuge statische Klassen, die Ihre Objekte enthalten. So wird die Anzahl der Objekte, auf die Sie zugreifen können, durch die Schnittstelle, die Ihre statische Klasse bietet, wieder hergestellt. Static ist nicht schlecht, solange Ihre Anwendung skaliert.
Eine weitere gute Alternative zu Singletons ist das Monostate-Muster, in dem Sie eine Klasse haben, die private statische Felder implementiert, um das "Singleton" -Verhalten darzustellen.
Siehe:
Monostate
Monostate gegen Singleton
UPDATE: Es hilft mir oft, einen REST wie API zu behalten, auch für interne Programmstrukturen. Eine Klasse zu haben, die von überall aktualisiert wird und Benachrichtigungen an alle sendet, ist schwer zu kontrollieren, um Bedingungen und Endlosschleifen zu erhöhen (Update - & gt; Ereignis - & gt; Update - & gt; ...)
Erstellen Sie eine (statische oder nicht) Statusleiste, auf die Sie zugreifen können, wo Sie sie benötigen. Durch eine statische Klasse, in der Sie Zugriff auf Ihre Statusleiste erhalten, oder durch Dependency-Injection, wenn Sie solche Techniken verwenden (nicht für kleinere Projekte empfohlen). Jeder Aufruf Ihrer Statusleistenschnittstelle muss unabhängig von Ereignissen sein, die möglicherweise von der Statusleiste ausgelöst werden, um weitere Probleme mit erhöhten Bedingungen zu vermeiden. Stellen Sie sich das Statusleisten-Interface wie eine Website vor, die von anderen Teilen des Programms aufgerufen werden kann, um Informationen zu pushen und zu ziehen.
Sie könnten einfach das Muster Observer
verwenden und das StatusBar
als Listener zu Ihren 20 Objekten hinzufügen. Dies wird die Singletons eliminieren und SRP und DIP besser folgen, aber Sie müssen überlegen, ob es sich lohnt. Ein Singleton ist möglicherweise besser, wenn die Indirektion zu viel Komplexität hinzufügt und eine Abhängigkeitsinjektion nicht möglich ist.
Klassen hängen implizit von jeder Verwendung von Singleton und explizit von irgendwelchen Parametern im Konstruktor ab. Ich würde vorschlagen, eine Schnittstelle zu dem Singleton hinzuzufügen, so dass nur die benötigten Methoden den Klassen unter Verwendung der IStatusBar ausgesetzt wären. Dies ist mehr Code, erleichtert jedoch das Testen von Einheiten.
Es ist schwierig, Ratschläge zu geben, ohne mehr über die Architektur Ihrer Anwendung zu wissen, aber vielleicht sollten Sie die Abhängigkeitsinjektion in Betracht ziehen. Übergeben Sie beispielsweise eine StatusBar-Instanz an den Konstruktor jeder Klasse, die sie direkt verwendet.