Designentscheidung Singleton oder durchreichen
-
Hallo zusammen,
hab da mal ne Frage bezüglich Objektorientierung.
Sollte ich Klassen, die für das gesamte Projekt interessant sind, als Singleton
erstellen oder immer durchreichen ?Z.B. eine Klasse Optionen welche die Benutzeroptionen speichert
oder Konfiguration mit irgendwelchen Pfaden etc..Wie macht ihr das ?
Gruß
-
Besser durchreichen. Wenn es in ellenlange Parameterlisten auszuarten droht, kannst du dir überlegen, gewisse Typen zu einer eigenen Klasse zusammenzufassen.
-
Keine Ahnung ob das gerne gesehen wird.
Ich habe einen Namespace "Globals" in dem alle globalen Pointer vorhanden sind.
Ist vom Aufruf das gleiche wie eine statische Klasse, finde ich vom Design her aber schöner.Gruß
-
Kommt auf das Projekt an, würde ich aber mit großer Wahrscheinlichkeit als Singleton realisieren. Gerade bei Optionen kann sich die Menge der Klassen, die darauf zugreifen müssen, öfters mal ändern. Dann hast du keine Lust, an x Stellen Konstruktor-/Funktionsaufrufe anzupassen.
Alternativ bietet sich eine Klasse an, die alles enthält, was deine Klassen benötigen könnten, wie von Nexus vorgeschlagen. Diese Klasse kannst du nach Belieben erweitern, ohne dass du an anderen Stellen Änderungen vornehmen musst.
Trotzdem bläht es den Code ein wenig auf, meist unnötigerweise.Wenn ich die Singletonklasse besonders häufig brauche, dann kürze ich das mit einer globalen Referenz auf die Singletoninstanz ab. Dann kann ich z.B. gl,Return (für globalConfiguration) anstatt conf,Return,::geti,Return tippen.
-
theliquidwave schrieb:
Keine Ahnung ob das gerne gesehen wird.
Wird es nicht.

Und wenn nicht nur Bequemlichkeit als Kriterium nimmst, merkst du relativ schnell, wieso. Globale Variablen (Singletons sind nur eine leichte Abwandlung davon) bringen einige Probleme mit sich. Hier ein Zitat von mir aus einem älteren Thread:
Nexus schrieb:
Globale Variablen verleiten dazu, sich keine Überlegungen mehr über modulare Programmierung und Zugehörigkeit der einzelnen Programmbestandteile zu machen. Entsprechend kann das gesamte Design darunter leiden. Eine Lösung nur aus Bequemlichkeit zu bevorzugen ist meist eine schlechte Idee. Die Vorteile sind nur von kurzer Dauer, hingegen schlagen die Probleme erst mit der Zeit hinterrücks zu.
Zu diesen gehört in erster Linie die grosse Abhängigkeit, die zwischen globalen Variablen und den deren Nutzern entstehen. Das wirkt sich einerseits negativ auf die Kompilierzeit aus, andererseits verletzt es die Kapselung. Da der Zugriff auf globale Variablen von überall (zumindest in den inkludierenden Dateien) her erfolgen kann, wird es schwierig, die Benutzung zurückzuverfolgen und Fehler einzuschränken. Je weniger Informationen eine Klasse oder Funktion über ihre Umgebung hat, desto weniger Seiteneffekte kann sie haben. Durch ein strukturiertes Design bleiben die Aufgabenbereiche lokal und sauber voneinander getrennt, was die Wartung erleichtert, da beispielsweise schnell ersichtlich ist, wo eine Änderung durchgeführt werden muss. Potenzielle Fehler haben zudem eine grössere Chance, an Ort und Stelle behandelt werden zu können.
-
Athar schrieb:
Kommt auf das Projekt an, würde ich aber mit großer Wahrscheinlichkeit als Singleton realisieren. Gerade bei Optionen kann sich die Menge der Klassen, die darauf zugreifen müssen, öfters mal ändern. Dann hast du keine Lust, an x Stellen Konstruktor-/Funktionsaufrufe anzupassen.
Was für Funktionen muss ich denn aufrufen, die bei einem Singleton wegfallen?
Athar schrieb:
Alternativ bietet sich eine Klasse an, die alles enthält, was deine Klassen benötigen könnten, wie von Nexus vorgeschlagen. Diese Klasse kannst du nach Belieben erweitern, ohne dass du an anderen Stellen Änderungen vornehmen musst.
Trotzdem bläht es den Code ein wenig auf, meist unnötigerweise.Gutes Design bläht den Code meist auf, aber nicht unnötig. Eine Klasse, in die man alles packt, ist auch nicht gerade das Wahre. Ich bezog mich eher auf Fälle, in denen ohnehin eine semantische Zusammengehörigkeit existiert, und da ist eine entsprechende Klasse kein Overhead.
Athar schrieb:
Wenn ich die Singletonklasse besonders häufig brauche, dann kürze ich das mit einer globalen Referenz auf die Singletoninstanz ab. Dann kann ich z.B. gl,Return (für globalConfiguration) anstatt conf,Return,::geti,Return tippen.
Das Problem hast du auch nicht, wenn du lokale Referenzen und Zeiger einsetzt.
Nicht falsch verstehen: Es gibt berechtigte Anwendungsfälle für Singletons. Aber viel zu oft wird dieser Weg lediglich aufgrund der scheinbaren Einfachheit gewählt, obwohl Alternativen um einiges sinnvoller wären. Dafür zahlt man einen entsprechenden Preis (siehe vorherigen Beitrag).
-
Nexus schrieb:
Was für Funktionen muss ich denn aufrufen, die bei einem Singleton wegfallen?
Keine, jedoch muss entweder der Klasse das Singleton im Konstruktor übergeben werden oder den jeweiligen Memberfunktionen, die es benötigen.
Und da kommt es oft vor, dass eine Klasse, die das Singleton zuvor nicht benötigt hat (ich beziehe mich auf das Beispiel der Konfigurationsklasse), es nun doch benötigt, weil eine neue Option hinzugefügt wurde. In diesem Fall müssten Anpassungen vorgenommen werden.Gutes Design bläht den Code meist auf, aber nicht unnötig. Eine Klasse, in die man alles packt, ist auch nicht gerade das Wahre. Ich bezog mich eher auf Fälle, in denen ohnehin eine semantische Zusammengehörigkeit existiert, und da ist eine entsprechende Klasse kein Overhead.
Durchaus, aber gerade bei einer Konfigurationsklasse gibt es kaum Zusammengehörigkeit zu anderen Klassen, da sie meist das gesamte Projekt überspannt. Das ist allerdings auch eher ein Spezialfall.
Das Problem hast du auch nicht, wenn du lokale Referenzen und Zeiger einsetzt.
Nein, aber davor etwas Zusatzaufwand, was sich dann relativieren dürfte.
Nicht falsch verstehen: Es gibt berechtigte Anwendungsfälle für Singletons. Aber viel zu oft wird dieser Weg lediglich aufgrund der scheinbaren Einfachheit gewählt, obwohl Alternativen um einiges sinnvoller wären. Dafür zahlt man einen entsprechenden Preis (siehe vorherigen Beitrag).
Dem stimme ich gerne zu, eine Konfigurationsklasse halte ich aber als klar berechtigten Anwendungsfall.
-
Athar schrieb:
Dem stimme ich gerne zu, eine Konfigurationsklasse halte ich aber als klar berechtigten Anwendungsfall.
Kommt halt immer auf den konkreten Anwendungsfall an.
Was du aber machen kann, um zu evaluieren, ob du ein Singleton verwenden kannst ist, dass du dir überlegst, ob du vielleicht daran interessiert sein könntest das ganze mit verschiedenen Instanzen laufen zu lassen (die Überlegung kann auch sehr überzogen sein).
Übliches Beispiel. Der Logger. Wenn du jetzt denkst: na gut ich brauche ja nur einen Logger, also machen wir da ein Singleton draus kann man dagegen halten, dass du vielleicht daran interessiert bist verschiedene Logger für verschiedene Teile zu verwenden und die einen z.B über das Internet zu dir schicken lässt und andere einfach nur in einem File mitschreibst. Solch eine Überlegung kann man immer mal wieder machen und schlussendlich musst du selbst abschätzen was dir lieber ist. Die Einfachheit oder Flexibilität.
-
Hmm OK, danke euch.
also unter Konfigurationen bzw. Optionen verstehe ich Dinge, die bei start
des Programms feststehen und sich auch nicht mehr ändern.
Z.B. ein Konfigfile, welches im Programmverzeichnis liegt ändert sich nicht, auch
wenn ich 20 Instanzen irgendeiner Klasse erstelle.Viele Wege führen nach Rom, ich werd einfach mal testen was mir besser gefällt

Gruß