La Microsoft.Xna.Framework.Game
clase tiene una propiedad de Servicios que permite al programador agregar un servicio a su juego al proporcionar el tipo de la clase y una instancia de la clase al método Agregar.
Ahora, en lugar de tener que pasar un AudioComponent
a todas las clases y métodos que lo requieren, simplemente pasa su Game
instancia y busca el servicio. ( Localizador de servicio )
Ahora, debido a que los juegos tienen muchos servicios (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager, etc.), básicamente pasarás el Juego a todo.
Entonces, ¿por qué no hacer de estas instancias un Singleton? Bueno, porque los Singleton son malos porque tienen un estado global, evitan las pruebas y hacen que su diseño sea mucho más frágil. Los localizadores de servicios se consideran igualmente un antipatrón para muchos porque en lugar de simplemente pasar la dependencia a un objeto, se pasa un localizador de servicios (el Juego) que combina esa clase con el resto de los servicios.
Entonces, ¿por qué se recomiendan los servicios en XNA y el desarrollo de juegos? ¿Es porque los juegos son diferentes de los programas normales y están altamente entrelazados con sus componentes y tener que pasar todos los componentes necesarios para el funcionamiento de una clase sería muy engorroso? ¿Son los servicios de juegos en ese momento un mal necesario en el diseño de juegos? ¿Existen alternativas que no impliquen largas listas de parámetros y acoplamiento?
fuente
Respuestas:
No creo que todos estén de acuerdo en que los localizadores de servicios son malos. Los Localizadores de servicios proporcionan una forma de desacoplar funcionalidades importantes que todos necesitan de su implementación real. Los localizadores de servicios también proporcionan una forma de intercambiar servicios en tiempo de ejecución. Además, no creo que sea cierto que deba pasar el localizador de servicios por todas partes. Creo que puedes acceder desde cualquier lugar. Mientras que una clase de juego con globals necesitaría pasarse unas mil veces por cuadro (lo que causaría un mal rendimiento).
Para hacer la diferencia entre el localizador de servicios y una clase con globales un poco más clara, considere el siguiente ejemplo:
Estoy haciendo un juego y uso un objeto de clase gameA que tiene una variable global: el cargador de contenido. Ahora, en mi próximo juego, no quiero usar la clase gameA sino crear una nueva clase gameB. Ahora tengo que volver a agregar los globales del juego A al juego B, que es un trabajo extra. También se hace difícil configurar el tipo de cargador de contenido que quiero. Digamos que tengo un juego que se ejecuta tanto en la PC como en la Xbox. En la PC, quiero un cargador de contenido que también pueda abrir un cuadro de diálogo 'abrir archivo'. Mientras estoy en XBOX definitivamente no quiero esto. Al tener un archivo de configuración, incluso puedo cambiar el cargador de contenido a la mitad del juego, incluso desde otro lugar que no sea la clase gameA, sin hacer públicos todos los globals en gameA.
Ahora considere que estoy usando un localizador de servicios. Siempre puedo seguir usándolo. E incluso qué tipo de servicios hay pueden ser diferentes todo el tiempo. También es cierto que ni siquiera me preocupará su implementación, siempre que tengan una interfaz común. (Aunque también podría usar eso en un gamA como clase).
De todos modos, creo que los servicios del juego te resultarán bastante útiles. Todos los que conozco lo usan. Para ayudarte un poco más. He creado una pequeña clase de ayuda en torno a los servicios de juegos para que puedas echar un poco menos de tiempo todo el tiempo: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager -and-graphicsdevice-anywhere-anytime-the-gameservicecontainer / Lo uso bastante.
fuente
return (T)Instance.GetService(typeof(T));
es.Service
sufijo redundante al final de cada método.AddService
método Servicios toma un tipo es para que pueda especificar la interfaz del servicio. Por ejemplo,Services.AddService(typeof(IGraphicsDeviceManager), graphics);
. Luego, al recuperar el servicio, puede especificar la interfaz como el tipo y enviarla a la subclase elegida.Los Singletons generalmente toman muchos rasgos útiles y los agrupan en un horrible híbrido que le brinda varias cosas que no desea junto con cualquier parte que quisiera. (¿Fueron características de 'crear a pedido'? ¿Alcance global? ¿Cumplimiento de al menos una instancia? ¿Prohibición de múltiples instancias?)
No puedes evitar el acoplamiento por completo. Las cosas usan otras cosas y sin eso su programa no hace nada. Entonces, la única pregunta real es en qué nivel de abstracción se encuentra.
La mayoría de los textos sobre orientación a objetos hacen una distinción entre Composición y Agregación. Es importante conocer la diferencia conceptual entre algo que posee y algo que conoce. Desafortunadamente, la mayoría de los lenguajes modernos no tienen una distinción clara aquí, y una referencia a un objeto podría significar cualquiera de estas cosas. (Irónicamente, C ++ hace un mejor trabajo, si utiliza los distintos tipos de punteros inteligentes).
Una forma en que puede aclarar la composición y la agregación en su código es mediante el uso de servicios para objetos agregados. Los servicios son una forma de proporcionar acceso a cosas que no posee, pero que puede usar.
No creo que sean universalmente recomendados en el desarrollo de juegos.
fuente