Singleton vs unnamed namespace



  • volkard schrieb:

    Eisflamme schrieb:

    Und was benutzt Du dann von beiden Varianten lieber?
    Also verbietest Du Mehrfachinstanziierung von Einmal-Objekten nicht?

    Normalerweise nicht. Im nächsten Programm will ich zwei Welten haben. Oder zwei Drucker.

    Muss sagen, das argument verstehe ich irgendwie nie so richtig. Normalerweise ist es einfacher ein Programm so zu schreiben, dass es von bestimmten Dingen nur eines gibt, weil man halt nur einen Fall prüfen muss. D.h. wenn ich mein Programm nur auf eine "Welt" auslege, kann ich eben nicht eine zweite einfach erstellen und das wird dann schon alles gutgehen. Entweder also programmierst du von Anfang an so das du x Welten erwartest, und machst dir falls du es nie braucht völlig unnötige Arbeit, oder aber du erlaubst es ein Objekt zu kopieren das logisch gesehen eben nicht kopiert werden darf.

    Ein Objekt das singleton ist mehrfach zu erlauben ist erstmal ne sehr einfach aufgabe.. Konstruktor public, getInstance oder so weg, dann variable global machen (oder aber auf dependency injection umstellen wenn man will). Aufrufe noch korrigieren und fertig. Dass das ganze mit einer dann tatsächlich zweiten Instanz des ehemaligen Singletons dann noch logisch funktioniert ist die interessantere und deutlich schwierigere frage. Wenn die beiden Welten nämlich tatsächlich vollständig unabhängig voneinander wären, könnte ich das programm ja einfach 2 mal starten. Da hat dot irgendwie recht, nur weil ich etwas nur einmal brauche ist es noch kein Grund für ein singleton.

    Vielleicht hab ich da eine etwas andere Philosophie, aber wenn ich erlaube das ein objekt kopiert wird/mehrfach erstellt wird dann will ich mir auch sicher sein dass es intuitiv und einwandfrei funktioniert. Auch wenn ich 3 Jahre später nachdem ich alles vergessen habe nochmal drüber schau. Aus demselben Grund mach ich auch operator= und copyctor private falls ich nach den aktuellen Anforderungen nicht klar entscheiden kann, was der eigentlich machen soll (und ich ihn noch eh nicht brauche).



  • kleiner Troll schrieb:

    Ein Objekt das singleton ist mehrfach zu erlauben ist erstmal ne sehr einfach aufgabe.. Konstruktor public, getInstance oder so weg, dann variable global machen (oder aber auf dependency injection umstellen wenn man will). Aufrufe noch korrigieren und fertig.

    Äh.
    Du hast sowas noch nie in einem grösseren Projekt gemacht, oder?
    Die Kleinigkeit "Aufrufe korrigieren" kann Tage dauern.



  • volkard

    theApp ist global und nicht static in der main.cpp, theWorld lokal und nicht static in der main(), Hilfstabellen zum Speichermanager sind dort im anonymous namespace also global und static, der Systemdrucker ist ein Meyers-Singleton also lokal und static, die Winsock-DLL hat die Tendenz dazu, im anonymous namespace der Socket.cpp zu liegen also lokal und static, kann aber auch durchgereicht werden also lokal und nicht static.

    Hmm... Wieso sind manche Dinge statisch und andere nicht? Global und lokal verstehe ich, das hat einfach mit den Zugriffsrechten zu tun bzw. gibt es für Kapselung halt lokal + Zugriffsmethode.

    Oder meinst Du ein anderes static als das mit dem static -Schlüsselwort? Und ich nehme an, mit global + nicht-static meinst Du nicht, dass das innerhalb der main()-Funktion deklariert ist, oder? Falls doch, inwiefern ist das denn global?

    dot:
    Die Punkte sind mir schon bewusst, danke. 🙂



  • Naja, was ist für dich "größer"?
    200k+ Zeilen? Nö hab ich zugegebenermaßen nicht.
    20k+ Zeilen? Jop.

    Sicher ist das nicht ne Sache von 5 Minuten, zumindest je nachdem wie tief das Singleton im Programm verankert ist.. Aber da es prinzipiell eine einfache Aufgabe ist muss man sich nicht so viele Sorgen um bugs die man einführen würde während dieser arbeit machen.

    "Tage" dauern würd ich für übertrieben halten,zumindest wenn man die variante mit der globalen variable nimmt.
    Kann man ja einfach nach namespace::GetInstance() suchen und das entsprechend ersetzen. Logisch muss man am code ja überhaupt nichts ändern.

    Schwieriger wirds natürlich wenn man auf dependency injection umstellt. Aber auch das seh ich als machbar an - vorallem als viel weniger arbeit als ein Riesenprogramm auf spezifikationen auszulegen, dies in 80% der Fälle nie brauchen wird.



  • kleiner Troll schrieb:

    volkard schrieb:

    Eisflamme schrieb:

    Und was benutzt Du dann von beiden Varianten lieber?
    Also verbietest Du Mehrfachinstanziierung von Einmal-Objekten nicht?

    Normalerweise nicht. Im nächsten Programm will ich zwei Welten haben. Oder zwei Drucker.

    Muss sagen, das argument verstehe ich irgendwie nie so richtig. Normalerweise ist es einfacher ein Programm so zu schreiben, dass es von bestimmten Dingen nur eines gibt, weil man halt nur einen Fall prüfen muss. D.h. wenn ich mein Programm nur auf eine "Welt" auslege, kann ich eben nicht eine zweite einfach erstellen und das wird dann schon alles gutgehen. Entweder also programmierst du von Anfang an so das du x Welten erwartest, und machst dir falls du es nie braucht völlig unnötige Arbeit, oder aber du erlaubst es ein Objekt zu kopieren das logisch gesehen eben nicht kopiert werden darf.

    Tut mir leid, aber ich programmiere zuerst ein Game mit nur einer Welt. Und denke dabei absolut nicht, daß mehrere Welten möglich wären. Und dann wenn ich es zum Multi-Player-Game ausbauen will, wäre ich verratzt, wenn ich die Welt-Klasse (ohne Not!) zum Singleton gemacht hätte.



  • kleiner Troll schrieb:

    Ein Objekt das singleton ist mehrfach zu erlauben ist erstmal ne sehr einfach aufgabe.. Konstruktor public, getInstance oder so weg, dann variable global machen (oder aber auf dependency injection umstellen wenn man will). Aufrufe noch korrigieren und fertig.

    Falsch.
    Weil es ein Singleton war, haben die Armeen und Häuser, die Dialoge und Buttons NICHT gespeichert, auf welche Welt sie wirken, denn es gibt ja nur eine.
    Gibt es auf einmal zwei Welten, muß alles neu angefaßt werden.
    Das Singleton-Versprechen ist so stark, das tut man nicht ohne Not mal dahinsagen. Jedenfalls ich nicht.

    kleiner Troll schrieb:

    Aus demselben Grund mach ich auch operator= und copyctor private falls ich nach den aktuellen Anforderungen nicht klar entscheiden kann, was der eigentlich machen soll (und ich ihn noch eh nicht brauche).

    So ich auch.



  • Eisflamme schrieb:

    Hmm... Wieso sind manche Dinge statisch und andere nicht?

    Bei den globalen: Aus Tradition, nur aus Tradition, ohne, daß das besonders sinnvoll wäre.



  • Vollkommen falsch! Falsch. Falsch. Falsch. Falsch. Falsch.

    Dazu zitiere ich mich einfach mal selbst

    Entweder also programmierst du von Anfang an so das du x Welten erwartest, und machst dir falls du es nie braucht völlig unnötige Arbeit, oder aber du erlaubst es ein Objekt zu kopieren das logisch gesehen eben nicht kopiert werden darf.

    Der Text ging eben unter der Annahme, dass das restliche Programm bereits mit mehreren instanzen umgehen kann.

    Du bist also der Meinung du schreibst stunden um stunden code um mehrere Welten zu unterstützen die du vielleicht mal brauchen KÖNNTEST? Bitte, verbiete ich dir nicht. Ich spar mir diese Arbeit - und mach konsequenterweise dann eben die Instanz, dies nur einmal geben darf zu einem singleton. Und falls sich doch tatsächlich die Anforderung ändert, kann ich diese Änderungen nachliefern. Das es syntaktisch bis dahin ein singleton war stört mich nicht weiter, weil eben nur das umzustellen ist ein moderator wenn auch zugegebenermaßen relevanter aufwand. Der logische/Design- Aufwand ist deutlich größer - egal ob man das jetzt von Anfang an macht oder nachholt.
    Nur häufig baut man sich halt nunmal Flexibilität mit viel mühen die man niemals braucht. Man kann sich natürlich wunderbar streiten was mehr arbeit macht, nachrüsten oder alles "richtig" machen damit man, falls man später etwas tatsächlich braucht weniger arbeit hat. Ist auch eine Frage wie wahrscheinlich es ist das sich entsprechende Anforderungen ändern. Muss man abschätzen, und wenn ich der Meinung bin es ist unwahrscheinlich das ichs später brauche mach ich ein singleton draus, inklusive vereinfachter logik. Deswegen überzeugt mich dieses Gebetsmühlenartige "aber man könnte es später ja mehrmals brauchen" auch nicht. Diese Aussage ist zwar imho völlig korrekt, aber leider nicht das einzige, was es zu beachten gibt.

    Und btw, auch im multiplayer gibt's nur eine Welt. Es gibt mehrere Spieler, aber (vom Modell her) immer noch eine Welt. Oder spielt dein Multiplayer in zwei verschiedenen leveln? (tatsächlich hat natürlich jeder seine eigene Kopie, und um das zu synchronisieren gibt's halt oft einen server der DIE EINE Welt hält und entscheidet was jetzt wie ist - die anderen haben eher nur ein Abbild)



  • Nur falls sich jemand wundert, Volkard hat nachdem ich zitiert habe seinen Text noch leicht geändert. (darfst gerne meinen post oben korrigieren und den hier löschen, inhaltlich ändert sich ja nichts)



  • Viele Klassen kann man doch schreiben und sie nur einmal benutzen. Oft ist es kein Problem sie mehrfach zu nutzen bzw. erfordert das nur wenige Erweiterungen. Die Klasse zum Singleton zu machen ist da sogar mehr Arbeit.



  • Sowas würd ich auch nicht zum Singleton machen. Wenn mehrere Instanzen einer Klasse kein Problem sind, gibt es ja keinen Grund mehrere Instanzen einer Klasse zu verbieten. Beispiel: Eine Konsole zur Eingabe von Befehlen (z.B. zum debuggen) während dem laufenden Programm. Wenn das abfangen der Tastatureingaben entsprechend gebaut ist, gibt's da kein Problem davon 5 auf einmal zu haben - selbst wenn man nur eine auf einmal sinnvoll verwenden kann.
    Andersrum würde ich die Art und Weise wie ich Tastatureingaben handhabe nicht ändern, nur um 5 solche Konsolen starten zu können. Das lass ichs dann lieber als singleton.



  • Wenn Du eine Klasse bastelst, ist es aber doch immer so, dass alles darin Gebaute für Mehrfachinstanziierung klappt. Du erzeugst dort benötigte Objekte, die am Ende wieder zerstört werden, und alles Verwendete kann man über die Methoden beeinflussen und nutzen.

    So was wird naturgemäß nicht zum Singleton gemacht. Aus deinen Aussagen ging hervor, dass Du eine Klasse, die nicht mehrere Instanzen haben würde, lieber zum Singleton machen würdest. Später schränkst Du das auf Klassen ein, bei denen eine Verwendung von mehreren Instanzen zusätzlichen Aufwand benötigen würde, sodass Du diese dann, falls es eh erstmal nur eine logische Instanz gibt, zum Singleton machst.

    Aber was für Klassen sollen das denn sein? Die meisten sind eben schon durch den Aufbau einer Klasse mit ctor/dtor an sich so gebaut, dass man die mehrfach nutzen kann, das ist der Standard und nicht andersrum.

    Und volkard meint nur, wenn es nicht absolut auszuschließen ist, dass man eine Klasse "Universum" mehrfach nutzen wird, sollte man die eben nicht zum Singleton machen, auch wenn die vorläufige Planung nur ein Objekt vorsieht.



  • Eisflamme schrieb:

    Und volkard meint nur, wenn es nicht absolut auszuschließen ist, dass man eine Klasse "Universum" mehrfach nutzen wird, sollte man die eben nicht zum Singleton machen, auch wenn die vorläufige Planung nur ein Objekt vorsieht.

    Nicht ganz. Auch wenn ich absolut ausschließen kann, daß man eine Klasse "Universum" mehrfach nutzen werde, mache ich sie nicht einfach zum Singleton. Sondern erst, wenn ich verbieten muß, daß es sie mehrfach gibt. Zum Beispiel, weil es ich der Einfachheit halber nicht durchreichen will. Die Konsole zum Beispiel, falls es eh sowas wie Fenster gibt, Eingabedialoge, dann kann das Spiel ja schon die Tastatureingabe ans aktive Fenster/Dialog/Editbox weiterleiten. Da gibt es überhaupt keinen Grund, die Konsole zum Singleton zu machen. Allein, ich lege nur eine davon an.



  • Aus deinen Aussagen ging hervor, dass Du eine Klasse, die nicht mehrere Instanzen haben würde, lieber zum Singleton machen würdest

    Nein, das ist ein notwendiger Grund, kein hinreichender. Nur weil ich denke ich brauch nur eins davon, mach ichs noch nicht zum singleton. Ein singleton wirds dann, wenn ich denke es wird nur eins davon geben und wenn es mehrere geben würde, würde es probleme verursachen um die ich mich kümmern müsste.
    Ein Beispiel wäre eine Klasse die ein archiv öffnet (und ich brauche in dem Programm nur ein enziges archiv) und daten rein und raus schreibt. Gäbe es das mehrmals, müsste ich das archiv immer wieder schließen, um anderen instanzen der Klasse zugriff auf dasselbe archiv zu erlauben. Verzögertes schreiben oder ähnliches muss ich dann alles koordinieren. Gibt's das nur einmal, weil ichs nur einmal brauche kann ich mir sparen mich um solche Probleme zu kümmern.
    Ich hab also entweder die wahl mich um jede beliebige kombination zu kümmern wie man diese Klasse verwenden könnte, mit allen methoden die sich ins gehege kommen könnten - oder ich verbiete einfach mehr als eine instanz.

    Die meisten sind eben schon durch den Aufbau einer Klasse mit ctor/dtor an sich so gebaut, dass man die mehrfach nutzen kann, das ist der Standard und nicht andersrum.

    Natürlich ist bei einem Programm mit mehr singletons als normalen klassen zu 99% irgendwas falsch gelaufen. In den meisten fällen stellt sich aber die Frage nicht, weil man naturgegeben die meisten dinge mehrmals braucht. Bei den Dingen die man normalerweise nur einmal braucht, gibt es auch einen Grund dafür WARUM das oft so ist.

    Die Konsole zum Beispiel, falls es eh sowas wie Fenster gibt, Eingabedialoge, dann kann das Spiel ja schon die Tastatureingabe ans aktive Fenster/Dialog/Editbox weiterleiten. Da gibt es überhaupt keinen Grund, die Konsole zum Singleton zu machen. Allein, ich lege nur eine davon an.

    Dem stimme ich zu. Der wichtige Punkt hier ist halt das "falls". (auch wenn eventuell die Konsole ein schlechtes Beispiel von mir war). Denn falls es sowas nicht gibt, mache ich es ganz natürlich zum singleton und mach mir nicht die Mühe dass es das, was hinter dem "falls" steht erstmal zu implementieren. Ich seh da gar keinen Grund dafür.
    Absolut ausschließen das man etwas mehrfach nutzen will kann man doch eigentlich eh nie. "Man könnte ja mal 2 brauchen" als Grund zu sehen in einem Fall kein Singleton zu machen bedeutet also, nie welche zu verwenden. Und dem muss ich widersprechen.

    Nur mal um etwas von Verhältnissen zu reden: Für 90-95% des codes gibt's imho keinen Grund Singletons zu machen. Und beim rest muss man sichs halt überlegen. Gibt ja noch andere Gründe die dagegen Sprechen - afaik beißt sich das pattern mit unit-testing.



  • Dann seid ihr zwei euch doch etwa einig. Immer diese Kommunikationsschwierigkeiten.

    Wo waren wir davor?



  • kleiner Troll schrieb:

    Naja, was ist für dich "größer"?
    200k+ Zeilen? Nö hab ich zugegebenermaßen nicht.
    20k+ Zeilen? Jop.

    Naja, 20k ist noch eher klein.

    Sicher ist das nicht ne Sache von 5 Minuten, zumindest je nachdem wie tief das Singleton im Programm verankert ist.. Aber da es prinzipiell eine einfache Aufgabe ist muss man sich nicht so viele Sorgen um bugs die man einführen würde während dieser arbeit machen.

    "Tage" dauern würd ich für übertrieben halten,zumindest wenn man die variante mit der globalen variable nimmt.
    Kann man ja einfach nach namespace::GetInstance() suchen und das entsprechend ersetzen. Logisch muss man am code ja überhaupt nichts ändern.

    Du willst nen Singleton gegen eine globale Variable austauschen? Soll das ein Scherz sein? Was soll das bitte bringen?

    Schwieriger wirds natürlich wenn man auf dependency injection umstellt. Aber auch das seh ich als machbar an - vorallem als viel weniger arbeit als ein Riesenprogramm auf spezifikationen auszulegen, dies in 80% der Fälle nie brauchen wird.

    Wie oft hast du es denn schon gemacht?
    Man abgesehen davon dass die Alternative zu nem Singleton nicht unbedingt Dependency-Injection heissen muss.


Anmelden zum Antworten