La Microsoft.Xna.Framework.Game
classe a une propriété Services qui permet au programmeur d'ajouter un service à son jeu en fournissant le type de la classe et une instance de la classe à la méthode Add.
Maintenant, au lieu d'avoir à passer un AudioComponent
à toutes les classes et méthodes qui en ont besoin, il vous suffit de passer votre Game
instance et de rechercher le service. ( Localisateur de services )
Maintenant, parce que les jeux ont de nombreux services (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager, et cetera), vous allez maintenant passer le jeu à tout.
Alors pourquoi ne pas simplement faire de ces instances un singleton? Eh bien, parce que les singletons sont mauvais parce qu'ils ont un état global, empêchent les tests et rendent votre conception beaucoup plus fragile. Les localisateurs de services sont également considérés comme un anti-modèle pour beaucoup car au lieu de simplement transmettre la dépendance à un objet, vous passez un localisateur de services (le jeu) qui couple cette classe avec le reste des services.
Alors pourquoi les services sont-ils recommandés dans XNA et le développement de jeux? Est-ce parce que les jeux sont différents des programmes réguliers et sont étroitement liés à leurs composants et devoir passer tous les composants nécessaires au fonctionnement d'une classe serait très lourd? Les services de jeux sont-ils alors un mal nécessaire dans la conception de jeux? Existe-t-il des alternatives qui n'impliquent pas de longues listes de paramètres et de couplage?
la source
Réponses:
Je ne pense pas que tout le monde convienne que les localisateurs de services sont mauvais. Les localisateurs de services permettent de découpler des fonctionnalités importantes dont tout le monde a besoin de leur mise en œuvre réelle. Les localisateurs de services permettent également d'échanger des services au moment de l'exécution. De plus, je ne pense pas qu'il soit vrai que vous devez faire circuler le localisateur de services partout. Je pense que vous pouvez y accéder de partout. Alors qu'une classe de jeu avec des globaux devrait être transmise environ mille fois par image (ce qui entraînerait de mauvaises performances).
Pour faire la différence entre le localisateur de service et une classe avec des globaux un peu plus clair, considérons l'exemple suivant:
Je fais un jeu et j'utilise un objet de classe gameA qui a une variable globale: le chargeur de contenu. Maintenant, dans mon prochain jeu, je ne veux pas utiliser la classe gameA mais créer une nouvelle classe gameB. Je dois maintenant ajouter à nouveau les globaux de gameA à gameB qui est un travail supplémentaire. Il devient également difficile de configurer le type de chargeur de contenu que je souhaite. Disons que j'ai un jeu qui fonctionne à la fois sur PC et sur XBOX. Sur le PC, je veux un chargeur de contenu qui peut également ouvrir une boîte de dialogue «Ouvrir un fichier». Alors que sur la XBOX, je ne veux vraiment pas cela. En ayant un fichier de configuration, je peux même à mi-chemin dans le jeu changer facilement le chargeur de contenu, même ailleurs que dans la classe gameA, sans simplement rendre les globaux de gameA tous publics.
Considérez maintenant que j'utilise un localisateur de services. Je peux toujours continuer à l'utiliser. Et même le type de services peut être différent à tout moment. Il est également vrai que je ne me soucierai même pas de leur mise en œuvre tant qu'ils auront une interface commune. (Bien que je puisse également l'utiliser dans une classe de type gamA).
Quoi qu'il en soit, je pense que vous trouverez les services de jeux assez pratiques. Tout le monde que je connais l'utilise. Pour vous aider un peu plus. J'ai créé une petite classe d'aide autour des services de jeu afin que vous puissiez faire un peu moins de casting tout le temps: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager -et-graphicsdevice-Anywhere-Anytime-the-Gameservicecontainer / Je l'utilise beaucoup.
la source
return (T)Instance.GetService(typeof(T));
.Service
suffixe redondant à la fin de chaque méthode.AddService
méthode Services prend un type est que vous puissiez spécifier l'interface du service. Par exempleServices.AddService(typeof(IGraphicsDeviceManager), graphics);
,. Ensuite, lors de la récupération du service, vous pouvez spécifier l'interface comme type et la caster dans la sous-classe choisie.Les singletons prennent généralement beaucoup de traits utiles et les regroupent dans un horrible hybride qui vous donne plusieurs choses que vous ne voulez pas ainsi que le bit que vous vouliez. (S'agissait-il de caractéristiques de «création à la demande»? Portée mondiale? Application d'au moins une instance? Interdiction de plusieurs instances?)
Vous ne pouvez pas éviter complètement le couplage. Les choses utilisent d'autres choses et sans cela, votre programme ne fait rien. La seule vraie question est donc de savoir à quel niveau d'abstraction elle se situe.
La plupart des textes sur l'orientation des objets font une distinction entre la composition et l'agrégation. Il est important de connaître la différence conceptuelle entre quelque chose que vous possédez et quelque chose que vous connaissez. Malheureusement, la plupart des langues modernes n'ont pas de distinction claire ici, et une référence à un objet pourrait signifier l'une ou l'autre de ces choses. (Ironiquement, C ++ fait un meilleur travail, si vous utilisez les différents types de pointeurs intelligents.)
Vous pouvez rendre la composition et l'agrégation claires dans votre code en utilisant des services pour les objets agrégés. Les services sont un moyen de donner accès à des choses que vous ne possédez pas, mais que vous pouvez utiliser.
Je ne pense pas qu'ils soient universellement recommandés dans le développement de jeux.
la source