Ich habe unzählige Male von den Fallstricken der Singletons / Globals gehört und verstehe, warum sie so oft verpönt werden.
Was ich nicht verstehe, ist, was die elegante, unordentliche Alternative ist. Es scheint, dass die Alternative zur Verwendung von Singletons / Globals immer darin besteht, Objekte eine Million Ebenen tiefer durch Ihre Engine-Objekte zu leiten, bis sie die Objekte erreichen, die sie benötigen.
Zum Beispiel lade ich in meinem Spiel einige Assets vor, wenn das Spiel gestartet wird. Diese Assets werden erst viel später verwendet, wenn der Spieler durch das Hauptmenü navigiert und das Spiel betritt. Soll ich diese Daten von meinem Game-Objekt an mein ScreenManager-Objekt übergeben (obwohl nur ein Bildschirm diese Daten tatsächlich berücksichtigt), dann an das entsprechende Screen-Objekt und an einen anderen Ort?
Es scheint nur, dass ich globale Zustandsdaten gegen überfüllte Abhängigkeitsinjektionen eintausche und Daten an Objekte weitergebe, die sich nicht einmal um die Daten kümmern, außer um sie an untergeordnete Objekte weiterzugeben.
Ist dies ein Fall, in dem ein Singleton eine gute Sache wäre, oder gibt es eine elegante Lösung, die ich vermisse?
quelle
Wenn Sie nicht möchten, dass ein Teil des Codes einige Daten magisch "kennt", muss er irgendwie übergeben werden. Das heißt aber nicht, dass es nur durch Argumente weitergegeben werden muss.
Könnten Sie in Ihrem Beispiel nicht eine Art "AssetManager" haben, der die Assets lädt und speichert, und dann müsste dem ScreenManager nur ein Verweis darauf gegeben werden (wahrscheinlich bei der Erstellung)? In diesem Sinne übergeben Sie die Verweise auf die Assets, die in einem anderen Objekt eingeschlossen sind, und Sie können diese bei der Initialisierung einmal übergeben, anstatt sie bei Bedarf an die Blattfunktion weiterzugeben.
Nun, IMHO, dass AssetManager, die Art von Dingen, von denen Sie nur eines wollen, genauso gut ein Singleton sein könnte. Vorausgesetzt, Sie verstehen die Fallstricke und codieren sie speziell, um sie zu vermeiden (nehmen Sie an, dass auf Singleton gleichzeitig von mehreren Threads aus zugegriffen wird, und stechen Sie sich jedes Mal mit einer Gabel, wenn Sie etwas tun, das blockiert werden muss), und hauen Sie sich dann aus.
quelle
Ich denke Jason D hat absolut recht - so würde ich damit umgehen:
Das Spiel verfügt über eine Instanz von AssetManager, einem Objekt, von dem Sie ein beliebiges Asset nach Namen abrufen können.
Im Spiel:
Im ScreenManager:
Auf dem Bildschirm:
Jetzt haben alle Bildschirme Zugriff auf alle benötigten Assets. Dies ist nicht komplexer oder verrückter als die Verwendung von Globals oder Singletons, und Sie haben die Möglichkeit, zwei Instanzen von Game in derselben Anwendung ohne Konflikte auszuführen. Ich musste einmal ein Spiel machen, das aus 8 Minispielen bestand, die alle die gleichen Basisklassen / Frameworks hatten. Ich musste alle meine Globals / Singletons überarbeiten, um diesen Referenz-Passing-Stil zu verwenden, und ich habe nie zurückgeschaut. Die einzigen Dinge, die global sein sollten, sind Dinge, die nur einmal physisch existieren können, wie Audio, Networking, I / O usw.
quelle
Sie können das Factory-Muster verwenden, um Singleton zu ersetzen . Dann hat die Factory-Klasse die Kontrolle darüber, wie viele Instanzen Sie erstellen können, die Sie später leicht ändern können, wenn Sie feststellen, dass Sie mehr als eine benötigen
AssetManager
. Wie in diesem Artikel angegeben :Eine andere, eher eingeschränkte Möglichkeit besteht darin, die Klasse statisch zu machen (was meines Erachtens für einen AssetManager nicht machbar ist und nur in Sprachen möglich ist, die überhaupt statische Klassen haben). Dies funktioniert jedoch nur, wenn Sie keine Vererbung / keinen Polymorphismus benötigen. Es ist eine sehr unflexible Lösung:
Hierbei handelt es sich um statische Methoden, sie können jedoch auch auf statische Klassen angewendet werden.
quelle