Qué resuelve#
A veces necesitas un único objeto accesible desde cualquier parte: el gestor de la partida, el de audio, el de puntuación. El Singleton garantiza que solo existe una instancia y ofrece un punto de acceso global a ella.
// Desde cualquier script:
GameManager.Instance.SumarPuntos(10);Implementación en Unity#
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
public int puntuacion;
void Awake()
{
// Si ya existe otro, este sobra
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject); // sobrevive al cambiar de escena
}
public void SumarPuntos(int p) => puntuacion += p;
}Sin la comprobación if (Instance != null …) Destroy(...), cada vez que vuelvas a una escena que contiene el GameManager aparecería otro (y con DontDestroyOnLoad, se acumularían). Esa guarda al inicio de Awake es imprescindible.
El lado oscuro: por qué se abusa#
El Singleton es cómodo, y por eso se abusa de él. Sus problemas:
- Acoplamiento global: cualquier script puede tocar
GameManager.Instancedesde cualquier sitio. Cuando el proyecto crece, rastrear quién cambia qué se vuelve difícil. - Dependencias ocultas: una clase que usa cinco singletons no lo declara en ninguna parte; lo descubres leyendo su código.
- Difícil de testear: el estado global persiste entre pruebas.
- Orden de inicialización: si un
Awakeusa otro singleton que aún no se ha inicializado, peta.
Ni santo ni demonio. Para uno o dos gestores verdaderamente globales (audio, gestor de partida) es una solución pragmática y perfectamente válida. El problema aparece cuando todo se vuelve Singleton y el proyecto se convierte en una maraña de estado global. La clave es la moderación, no la prohibición.
Alternativas (para no abusar)#
- ¿Un gestor global de verdad (audio, partida), uno o dos? → Singleton está bien
- ¿Comunicar sistemas sin que se conozcan? → eventos (ver Eventos y delegados)
- ¿Datos/config compartidos? → un ScriptableObject compartido (ver ScriptableObject)
- ¿Una dependencia que una clase necesita? → inyéctala (asígnala por Inspector o por un instalador) en vez de buscarla globalmente
Cuándo NO usarlo#
- Para pasar datos entre dos clases concretas: una referencia directa o un evento es más claro.
- Para cualquier cosa que quieras poder testear de forma aislada.
- Cuando te descubras convirtiendo en Singleton la quinta clase: señal de que falta arquitectura.
Ponte a prueba#
Resumen#
El Singleton da una instancia única y accesible globalmente, ideal para uno o dos gestores (partida, audio). Impleméntalo con static Instance, la guarda contra duplicados en Awake y DontDestroyOnLoad. Úsalo con moderación: para comunicar sistemas prefiere eventos, para datos compartidos ScriptableObjects, y evita convertir todo en global.