Introducción
Hay una gran cantidad de patrones y antipatrones de programación. A menudo, el uso de patrones nos dicta la experiencia y el conocimiento real de sí mismos. En este artículo, quiero discutir con ustedes la aplicación del patrón Singleton , es decir, su implementación en la Red aplicada a Unity.
único
Noto que estoy escribiendo código en un equipo, por lo que tomo la mayor cantidad de trabajo posible dentro del código para descargar el equipo y eliminar la necesidad de pensar en algunas de las dificultades de implementar ciertos patrones en Unity.
Al estudiar la literatura sobre la Red 1 , en relación con esta pregunta 2, y como resultado del trabajo en varios proyectos, nació la siguiente clase:
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
private static T instance = null;
private bool alive = true;
public static T Instance
{
get
{
if (instance != null)
{
return instance;
}
else
{
T[] managers = GameObject.FindObjectsOfType<T>();
if (managers != null)
{
if (managers.Length == 1)
{
instance = managers[0];
DontDestroyOnLoad(instance);
return instance;
}
else
{
if (managers.Length > 1)
{
Debug.LogError($"Have more that one {typeof(T).Name} in scene. " +
"But this is Singleton! Check project.");
for (int i = 0; i < managers.Length; ++i)
{
T manager = managers[i];
Destroy(manager.gameObject);
}
}
}
}
GameObject go = new GameObject(typeof(T).Name, typeof(T));
instance = go.GetComponent<T>();
instance.Initialization();
DontDestroyOnLoad(instance.gameObject);
return instance;
}
}
set
{
instance = value as T;
}
}
public static bool IsAlive
{
get
{
if (instance == null)
return false;
return instance.alive;
}
}
protected void Awake()
{
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = this as T;
Initialization();
}
else
{
Debug.LogError($"Have more that one {typeof(T).Name} in scene. " +
"But this is Singleton! Check project.");
DestroyImmediate(this);
}
}
protected void OnDestroy() { alive = false; }
protected void OnApplicationQuit() { alive = false; }
protected virtual void Initialization() { }
}
Me enfocaré en varios aspectos.
Creación de objetos
Cuando se expande un proyecto, y aún más trabajando en equipo> 3 personas, a menudo surge una situación en la que la secuencia de creación de objetos se vuelve poco clara. Hablando estrictamente 3 , la secuencia de llamadas a Awake () es aleatoria (por supuesto, esto no es del todo cierto, y el proceso puede verse influenciado, pero la documentación es sagrada), por lo que es necesario eliminar este inconveniente molesto mediante la implementación de la propiedad Instance {get;} . Como resultado, tenemos acceso completo al singleton de Awake () de otras clases.
, Lazy, Awake() .
4-4, , Instance{get;}.
Unity — Awake(). , , Initialization(). (KISS).
, DI SD. . .
, , OnDestroy(), OnApplicationQuit() 5:
Did you spawn new GameObjects from OnDestroy?
, , , . , IsAlive(), , . , ...
Cada vez más, llego a la conclusión de que usando el paradigma de Unity es posible implementar mis proyectos sin Singleton. A menudo, la aplicación de este patrón hace que su código esté altamente conectado y extremadamente frágil.
Gracias.
Fuentes
- Richter J. "CLR a través de C #. Programación en Microsoft.NET # Framework 4.5 en C #", 2013
- https://www.codingame.com/playgrounds/1979/different-ways-to-implement-singleton-in--net-and-make-people-hate-you-along-the-way
- https://docs.unity3d.com/en/current/ScriptReference/MonoBehaviour.Awake.html
- https://ru.wikipedia.org/wiki/Design_Patterns
- Dickinson Chris "Unity 2017 Game Optimization, Second Edition", 2017