¿Es una mala idea tener Game1 estático en XNA?


10

¿Es realmente una mala idea tener mi Game1clase como estática? Como en este momento en mi Game1clase, tengo una clase llamada TileHandlerque maneja todo lo que tiene que ver con mi conjunto actual de fichas, y AnimalHandlerque maneja todos mis animales (sorprendentemente).

Ahora, si estoy dentro AnimalHandlery quiero verificar si un mosaico es transitable desde TileHandlerentonces, eso causa problemas o tengo que pasar una lista de mosaicos transitables AnimalHandler, lo que preferiría no hacer.

Lo que sería más fácil sería hacer Game1estática y luego AnimalHandlersimplemente ir Game1._tileHandler.WalkableTile(position).

Ahora no puedo ver nada inmediatamente incorrecto con esto o cualquier cosa que pueda causar algún problema, pero acabo de comenzar a usar clases estáticas, entonces, ¿alguien más conocedor ve alguna razón gigante por la que es una mala idea?

Respuestas:


9

Ahora no puedo ver nada inmediatamente incorrecto con esto o cualquier cosa que pueda causar algún problema, pero acabo de comenzar a usar clases estáticas, entonces, ¿alguien más conocedor ve alguna razón gigante por la que es una mala idea?

Cuando tienes un martillo nuevo y brillante, cada problema parece un clavo.

En general, no hay nada de malo con las clases y / o métodos estáticos, si se usan correctamente (para cosas que no tienen o dependen del estado por instancia). Sin embargo, en su caso, los está utilizando mal para ocultar una dependencia por instancia, confundiendo esto con la eliminación de la dependencia. También parece que está exponiendo los detalles de implementación de la Game1clase, lo que también es generalmente malo.

Aquí está el quid de tu problema:

... si estoy dentro AnimalHandlery quiero verificar si un mosaico es transitable desde TileHandlerentonces, eso causa problemas o tengo que pasar una lista de mosaicos transitables AnimalHandler, lo que prefiero no hacer.

Ignorando la posibilidad de que la AnimalHandlernecesidad de estos mosaicos pueda ser un mal diseño (con los nombres que ha elegido, es difícil decir los detalles de estas clases) por el momento ... si AnimalHandlernecesita una lista de mosaicos transitables, entonces necesita una lista de baldosas transitables. En general, es mejor hacer que las dependencias sean más explícitas que menos , ya que hace que el código sea más autodocumentado. Al pasar la lista directamente a AnimalHandler, explícitamente llama el hecho de que necesita dicha lista. Si, en cambio, hace que todo sea estático y público para que pueda acceder a la lista estática que se encuentra en otra parte del código, todo lo que debe hacer es ocultar la dependencia sin resolverla o eliminarla.

Para un juego pequeño que no necesita escalar, esto no será un problema, per se, pero puede llevarlo por el camino de un mal hábito, por lo que es posible que desee considerar no hacerlo. Por lo menos, tenga esto en cuenta para el próximo proyecto en el que trabaje.


¡Amén! Tocas un gran punto del que realmente no hablé en mi respuesta.
Nate

+1 ocultar las dependencias e introducir el estado global es realmente el problema aquí
cenizas999

4

La razón por la que llamar a TileHandler en un contexto estático no es el mejor diseño posible, es que combina componentes de su diseño que de otra manera podrían desacoplarse.

Si elige tener más de un TileHandler en el futuro, tendrá que hacer mucho trabajo para acomodar este cambio.

Si elige eliminar TileHandler, tendrá que hacer mucho trabajo para acomodar este cambio.

Supongamos que construye un nivel / zona diferente en el futuro, que maneja los mosaicos de una manera diferente a su TileHandler actual. Luego, debe tener una manera de especificar el método de manejo de mosaicos que debe usar, o debe llamar a un controlador diferente.

Si el TileHandler se pasó como un parámetro a los objetos que lo usan, entonces simplemente puede pasar uno diferente la próxima vez, o establecer un controlador de mosaico diferente en los objetos que lo usan más tarde.

Personalmente, accedo a muchas cosas en mis juegos XNA desde un contexto estático, y asumo que nunca tendré más de uno.

Si quieres poder reutilizar el código del motor de tu juego en tu próximo juego, es probable que tengas que reescribir muchas de las cosas que actualmente has escrito como estáticas.

En breve:

A favor de no usar contexto estático:

Pasar objetos como parámetros tanto como sea posible desacopla los elementos del juego y le permite modificarlos / reutilizarlos para los proyectos actuales o futuros con mayor facilidad. También le permite administrar la complejidad de grandes cantidades de código un poco más fácil (piense en tener cientos de administradores estáticos en su clase de juego, en un gran juego).

A favor del contexto estático:

Declarar y acceder a objetos desde un contexto estático hace que sea más fácil escribir juegos pequeños que no requieren cientos de administradores estáticos. Simplifica muchos métodos y constructores al no requerir uno o más parámetros adicionales a los que se accede estáticamente.



2

Cosas como TileHandler y AnimalHandler pondría un nivel más alto en una pantalla de juego. ¿Su pantalla de título necesita acceso al TileHandler y se inicializa cuando se carga el juego por primera vez? Probablemente no.

Echa un vistazo a la muestra de XNA State Management . Tiene mucho código allí, pero básicamente el juego base solo inicializa una pila de estados (o pantallas) del juego. Cada pantalla es bastante independiente de las demás y se ejecuta como una versión simplificada del Juego en sí. Su PlayScreen podría tener miembros estáticos para que sean accesibles para los componentes de PlayScreen.

En el juego base, utilizo algunas estadísticas, pero son cosas de muy bajo nivel como los lectores InputHelper, Log o Config. Son bastante estándar en todos los juegos, por lo que el motor base se puede portar rápida y fácilmente. Las pantallas son donde sucede la lógica del juego real. Entonces, respuesta corta: no, no creo que sea una mala idea en teoría, solo tenga cuidado con lo que hace estático. Una vez que sigas adelante y hagas algo estático, es una gran cantidad de trabajo si cambias de opinión.


0

Los puntos planteados aquí son todos buenos. En mi experiencia (que ciertamente está más orientada a las aplicaciones empresariales que a los juegos), existen excelentes usos para las clases estáticas y los miembros, y los he usado muchas veces. He descubierto que, a medida que crecen los requisitos y la complejidad, termino reciclando esas clases estáticas y convirtiéndolas en clases de instancia y empiezo a pasarlas.

El punto que me gustaría destacar es que, si usar una clase estática te ayuda a sacar este juego, hazlo, pero sigue haciendo lo correcto: implementa una interfaz o clase base para que sea más fácil extraerlo y convertirlo a una clase de instancia más adelante.

Una onza de prevención vale una libra de cura, así que asegúrate de que tu clase estática no te amarre, lo que dificulta el cambio. Es bastante fácil refactorizar un método usando una clase estática que implementa una interfaz para que acepte un nuevo parámetro de interfaz y use esa interfaz en lugar de la referencia de clase estática.


0

Sí, generalmente siempre es una mala idea.

Convirtiendo objetos que contienen datos cambiantes (es decir, cualquier cosa menos constantes de solo lectura y tablas de búsqueda) en clases estáticas es donde el buen diseño se sumerge.

  1. Promueve dependencias fortuitas que eliminan la modularidad y obstaculizan la reutilización del código. Suponga que desea escribir un editor para su juego: de repente tendría muchas clases llorando por algo Game1que no puede mover fácilmente a una biblioteca compartida.

  2. Su código se vuelve no comprobable. Las pruebas unitarias funcionan al aislar las clases individuales del resto burlándose o simulando sus dependencias (que deben mantenerse lo más mínimo posible). Cualquier clase estática es una responsabilidad porque se puede acceder en cualquier momento, llevar el estado a través de múltiples pruebas o requerir que se inicialice antes de que las pruebas puedan tener éxito.

  3. Oculta dependencias. Al igual que el antipatrón del proveedor de servicios (también empleado por XNA, Game.Services), sus clases pueden elegir dependencias que no ve en el exterior.

Este enfoque se vuelve especialmente venenoso si se combinan clases estáticas con llamadas de trenes de carga (cosas como las Game.Instance.ActorManager.Enemies.FindInRange(10)llamadas por los símbolos encadenados en forma de vagones de tren), donde los componentes de repente no solo requieren una Gameclase, sino una con una Instancepropiedad estática que devuelve algo con Una ActorManagerpropiedad que tiene una Enemiespropiedad que devuelve un objeto con un FindInRange()método.

La única excusa que aceptaría para escribir clases estáticas mutables sería que todavía está aprendiendo y no tiene la capacidad de aplicar consistentemente un buen diseño y un ojo entrenado para detectar malas decisiones todavía.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.