본문 바로가기

UNITY

UNITY_20231023[디자인 패턴-싱글톤]

싱글톤 패턴은 객체의 인스턴스를 오직 하나만 생성할 수 있도록 제약 환경을 만드는 패턴이다.

이 패턴을 사용함으로써 해당 객체는 다른 객체에서 전역적으로 접근할 수 있게 된다.

싱글톤 패턴을 MANAGER급 객체에 적용시키면 다른 오브젝트에서 이 MANAGER클래스의 요소를 쉽게 호출, 접근할 수 있다.

 

이때까지 진행한 프로젝트에 싱글톤 패턴을 적용하지 않은 경우는 한번도 없었을 정도로 아주 편리한 패턴이다.

처음에는 아래와 같이 싱글턴 패턴 코드를 작성했다.

sing System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;

    private void Awake()
    {
        Instance = this;
    }

또는

public class GameManager : MonoBehaviour
{
    [HideInInspector] public static GameManager Instance;
    
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else Destroy(gameObject);
    }

 

아주 단순하면서도 제 기능을 해내는 코드다.

다른 오브젝트의 스크립트에서 부를 때도 GameManger.Instance.GM요소 형식으로 부르면 된다.

 

하지만 이러한 MANAGER급 객체가 많아진다면? 게임, 오디오, UI, DATA 등 정말 많다.

이런 객체에 일일이 저런 코드를 쓸 것인가? 같은 코드를 반복해서 쓰는 것은 항상 지양해야 할 일이다.

또한, 한 객체를 싱글톤화 한지도 모르고 다른 곳에서 인스턴스화 해버리면? 그 싱글톤은 쓸모도 없어지고, 새롭게 만들어진 인스턴스를 언젠가 게임 내 오류를 일으킬 것이다.

 

위와 같은 위험을 방지하기 위하여 이전 프로젝트에서는 아래와 같은 싱글톤 코드를 사용했다.

 

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)
                {
                    GameObject obj = new GameObject(typeof(T).Name, typeof(T));
                    instance = obj.GetComponent<T>();
                }
            }
            return instance;
        }
    }

    public void Awake()
    {
        if(transform.parent != null && transform.root != null)
            DontDestroyOnLoad(this.transform.root.gameObject);
        else
            DontDestroyOnLoad(this.gameObject);

        Init();
    }

    public virtual void Init()
    {

    }
}

MONOBEHAVIOR를 상속받는 T라는 객체는 Singleton이라는 제네릭을 상속할 것이다.

SingleTon을 상속받는 GM은 아래와 같이 시작한다.

using UnityEngine;

public class GameManager : Singleton<GameManager>
{

}

GM은 Singleton제네릭을 상속받아 그 기능을 고스란히 사용할 수 있게 됐다.

 

이와 같은 방법으로 싱글톤이 필요한 객체에 일일이 같은 코드를 작성할 필요가 없게 되고, 객체의 생성와 파괴에 의한 성능 저하를 줄일 수 있다.