He escuchado innumerables veces sobre las trampas de Singletons / globals, y entiendo por qué a menudo están mal vistos.
Lo que no entiendo es cuál es la alternativa elegante y no desordenada. Parece que la alternativa al uso de Singletons / globals siempre implica pasar objetos un millón de niveles hacia abajo a través de los objetos del motor hasta que lleguen a los objetos que los necesitan.
Por ejemplo, en mi juego, precargo algunos recursos cuando se inicia el juego. Estos recursos no se utilizan hasta mucho más tarde cuando el jugador navega por el menú principal y entra al juego. ¿Se supone que debo pasar estos datos de mi objeto Juego a mi objeto ScreenManager (a pesar de que solo una Pantalla realmente se preocupa por estos datos), luego al objeto Pantalla apropiado y en cualquier otro lugar?
Simplemente parece que estoy intercambiando datos de estado global por inyección de dependencia desordenada, pasando datos a objetos que ni siquiera se preocupan por los datos, excepto con el propósito de pasarlos a objetos secundarios.
¿Es este un caso en el que un Singleton sería algo bueno, o hay alguna solución elegante que me falta?
fuente
Si no puede / no puede tener una parte del código mágicamente "saber" acerca de algunos datos, entonces tendrá que pasar de alguna manera. Sin embargo, eso no significa que necesariamente deba pasarse solo a través de argumentos.
En su caso de ejemplo, ¿no podría tener algún tipo de "AssetManager" que cargaría y almacenaría los activos, y luego el ScreenManager solo necesitaría una referencia a eso (probablemente en la creación)? En ese sentido, está pasando las referencias a los activos envueltos en otro objeto, y puede pasar eso una vez, en la inicialización, en lugar de pasarlo a la función de hoja cuando sea necesario.
Ahora, en mi humilde opinión, ese AssetManager, siendo el tipo de cosas de las que solo quieres una, podría ser un singleton. Siempre que comprenda las trampas y codifique específicamente para evitarlas (suponga que se accederá a singleton simultáneamente desde múltiples subprocesos y apuñale con un tenedor cada vez que haga algo que deba bloquear), luego déjese inconsciente.
fuente
Creo que Jason D tiene toda la razón: así es como lo manejaría:
El juego tiene una instancia de AssetManager, un objeto del que puede obtener cualquier activo por su nombre.
En el juego:
En ScreenManager:
En pantalla:
Ahora todas las pantallas tienen acceso a los activos que necesitan. Esto no es más complejo o loco que usar globals o Singletons, y tiene la opción de tener 2 instancias de Juego ejecutándose en la misma aplicación sin conflictos. Una vez tuve que hacer un juego que estaba compuesto por 8 minijuegos, todos compartiendo las mismas clases / framework base. Tuve que refactorizar todos mis globals / singletons para usar este estilo de aprobación de referencia, y nunca he mirado hacia atrás. Las únicas cosas que deberían ser globales son cosas que solo pueden existir físicamente una vez, como audio, redes, E / S, etc.
fuente
Puede usar el patrón Factory para reemplazar Singleton . Luego, la clase de fábrica tiene el control sobre cuántas instancias puede crear, que puede cambiar fácilmente más adelante cuando encuentre que necesita más de una
AssetManager
. Como se indica en este artículo :Otra posibilidad bastante limitada es hacer que la clase sea estática (lo cual no creo que sea factible para un AssetManager y solo es posible en lenguajes que tengan clases estáticas). Pero eso solo funciona si no necesita herencia / polimorfismo. Es una solución muy inflexible:
Se trata de métodos estáticos, pero también se puede aplicar a clases estáticas.
fuente