J'ai entendu d'innombrables fois les pièges des singletons / mondiaux, et je comprends pourquoi ils sont si souvent désapprouvés.
Ce que je ne comprends pas, c'est quelle est l'alternative élégante et non salissante. Il semble que l'alternative à l'utilisation de singletons / globaux implique toujours de faire passer des objets un million de niveaux à travers les objets de votre moteur jusqu'à ce qu'ils atteignent les objets qui en ont besoin.
Par exemple, dans mon jeu, je précharge certains éléments au démarrage du jeu. Ces ressources ne sont utilisées que bien plus tard lorsque le joueur navigue dans le menu principal et entre dans le jeu. Suis-je censé transmettre ces données de mon objet Game, à mon objet ScreenManager (malgré le fait qu'un seul écran se soucie réellement de ces données), puis à l'objet Screen approprié, et ailleurs?
Il semble juste que j'échange des données d'état globales pour une injection de dépendance encombrée, en passant des données à des objets qui ne se soucient même pas des données, sauf dans le but de les transmettre à des objets enfants.
Est-ce un cas où un Singleton serait une bonne chose, ou y a-t-il une solution élégante qui me manque?
la source
Si vous ne pouvez pas / ne pouvez pas avoir une partie du code comme par «connaissance» magique de certaines données, elles devront être transmises d'une manière ou d'une autre. Cependant, cela ne signifie pas qu'il doit nécessairement être passé uniquement par des arguments.
Dans votre exemple, ne pourriez-vous pas avoir une sorte de "AssetManager" qui chargerait et stockerait les actifs, et le ScreenManager n'aurait alors besoin que d'une référence à cela (probablement lors de la création)? En ce sens, vous transmettez les références aux actifs enveloppés dans un autre objet, et vous pouvez les transmettre une fois, lors de l'initialisation, plutôt que de les transmettre à la fonction feuille lorsque cela est nécessaire.
Maintenant à mon humble avis que AssetManager, étant le genre de chose dont vous ne voulez qu'une, pourrait tout aussi bien être un singleton. À condition de comprendre les pièges et de coder spécifiquement pour les éviter (supposez que le singleton sera accessible simultanément à partir de plusieurs threads et vous poignarder avec une fourchette chaque fois que vous faites quelque chose qui doit bloquer), puis assommez-vous.
la source
Je pense que Jason D a tout à fait raison - c'est ainsi que je gérerais cela:
Le jeu a une instance de AssetManager, un objet à partir duquel vous pouvez obtenir n'importe quel actif par son nom.
En jeu:
Dans ScreenManager:
À l'écran:
Tous les écrans ont désormais accès aux ressources dont ils ont besoin. Ce n'est pas plus complexe ou fou que d'utiliser des globales ou des singletons, et vous avez la possibilité d'avoir 2 instances de jeu en cours d'exécution dans la même application sans heurts. J'ai dû créer un jeu composé de 8 mini-jeux, partageant tous les mêmes classes de base / framework. J'ai dû refactoriser tous mes globals / singletons pour utiliser ce style de passage de référence, et je n'ai jamais regardé en arrière. Les seules choses qui devraient être globales sont des choses qui ne peuvent exister physiquement qu'une seule fois, comme l'audio, la mise en réseau, les E / S, etc.
la source
Vous pouvez utiliser le modèle Factory pour remplacer Singleton . Ensuite, la classe d'usine contrôle le nombre d'instances que vous pouvez créer, que vous pouvez facilement modifier plus tard lorsque vous en avez besoin de plusieurs
AssetManager
. Comme indiqué dans cet article :Une autre possibilité, assez limitée, est de rendre la classe statique (ce qui, je pense, n'est pas faisable pour un AssetManager et n'est possible que dans les langages qui ont des classes statiques). Mais cela ne fonctionne que si vous n'avez pas besoin d'héritage / polymorphisme. C'est une solution très rigide:
Il s'agit de méthodes statiques, mais elle peut également être appliquée à des classes statiques.
la source