두고두고 써먹는 싱글톤(SingleTon) 코드

싱글톤 패턴이란?

Unity 싱글톤 패턴은 특정 클래스가 게임 수명 기간 동안 하나의 인스턴스만 갖도록 하기 위해 Unity 게임 개발에서 일반적으로 사용되는 디자인 패턴입니다.

 

이 패턴은 게임 내에서 전역적으로 액세스할 수 있어야 하는 단일 리소스나 시스템(예: 게임 매니저, 오디오 매니저 또는 게임 설정 매니저)을 관리해야 할 때 유용합니다.

 

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}
Singleton Instance = Singleton.Instance;

 


일반적인 싱글톤 패턴

using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));
                
                if (instance == null)
                {
                    var ob = new GameObject(typeof(T).Name);
                    instance = ob.AddComponent<T>();
                }
            }
            
            return instance;
        }
    }

    protected void Awake()
    {
        if (instance == null)
        {
            instance = this as T;
            DontDestroyOnLoad(this.gameObject);
        }
        else if (instance != this)
        {
            Destroy(this.gameObject);
        }
    }
}

좀 더 진보된 싱글톤 패턴

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    public static T Instance { get; private set; }

    private static System.Action<T> s_onAwake;

    public static void WhenInstantiated(System.Action<T> action)
    {
        if (Instance != null)
            action(Instance);
        else
            s_onAwake += action;
    }

    protected virtual void Awake()
    {
        if (!enabled)
            return;

        if (Instance != null)
        {
            Debug.LogWarning($"Another instance of Singleton {typeof(T).Name} is being instantiated, destroying...", this);
            Destroy(gameObject);
            return;
        }
    
        Instance = (T)this;

        InternalAwake();

        s_onAwake?.Invoke(Instance);
        s_onAwake = null;
    }

    protected void OnEnable()
    {
        if (Instance != this)
            Awake();
    }

    protected virtual void InternalAwake() { }
}