상세 컨텐츠

본문 제목

1030 TIL - C# 제네릭 싱글톤

스파르타 코딩캠프/'24 Today I Learned

by lucar 2024. 10. 30. 20:50

본문

디자인 패턴 중에 싱글톤 이라는 패턴이 있다.

 

이전에 설명한 적이 있어서 자세한 설명은 생략할껀데

 

Unity에서 스크립트를 작성하다보면 정말 많은 양의 매니저들이 생겨난다.

 

GameManager, CharacterManager, QuestManager, ...

그리고 보통 매니저들은 DontDestroyOnLoad를 걸어서 씬 간의 이동에도 파괴되지 않도록 하고

그렇게 파괴되지 않은 수 많은 매니저들은 씬 간의 정보 교환이나 굵직한 스크립트를 넘겨주는 역할을 한다.

 

그리고 그 매니저들은 싱글톤 패턴을 주로 사용하게 되는데

 

수많은 싱글톤들을 일일히 작성하거나 복사 붙여넣기 하는 것도 지겹고

제네릭을 사용해서 상속받으면 끝인 형식으로 만들어보자.

 

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                GameObject obj = GameObject.Find(typeof(T).Name);
                if (obj == null)
                {
                    obj = new GameObject(typeof(T).Name);
                    instance = obj.AddComponent<T>();
                }
                else
                {
                    instance = obj.GetComponent<T>();
                }
            }
            return instance;
        }
    }
}

제네릭을 사용하여 선언 시점에 형식을 골라주면 모든 T가 해당 형식으로 변하게 된다.

 

게임매니저를 만들어보자.

 

public class GameManager : Singleton<GameManager>
{

}

끝이다.

 

내용을 조금 추가해서 다른 부분에서도 참조 가능한지 확인해보자.

 

public class GameManager : Singleton<GameManager>
{
    public Player Player;
}

Player 클래스를 참조할 수 있도록 해주고

Player 클래스에서 해당 부분을 this로 채우는 스크립트를 작성해보자.

 

public class Player : MonoBehaviour
{
    private void Awake()
    {
        GameManager.Instance.Player = this;
    }
}

에러 밑줄 조차 뜨지 않고 Instance.Player로 깔끔하게 연결된다.

 

참고로 DontDestoryOnLoad는 제네릭 클래스를 하나 더 생성하는게 좋은데

 

모든 싱글톤들이 DontDestroyOnLoad를 필요로 하지 않기 때문이다.

public class SingletonDontDestroy<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                GameObject obj = GameObject.Find(typeof(T).Name);
                if (obj == null)
                {
                    obj = new GameObject(typeof(T).Name);
                    instance = obj.AddComponent<T>();
                }
                else
                {
                    instance = obj.GetComponent<T>();
                }
            }
            return instance;
        }
    }
    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}

하지만 Awake부분을 virtual로 작성하여 오버라이드 할 시 실행이 안되게 작성할 수도 있겠다.

 

TTE

관련글 더보기