유니티/디자인패턴

[Unity] 유니티 C#) Singleton 패턴

새벽_글쓴이 2024. 12. 3. 10:37
반응형

싱글톤 패턴

클래스의 인스턴스가 게임 전체에서 단 하나만 존재하도록 보장하는 디자인 패턴

 

Unity에서 특히 유용한 이유

씬(Scene) 전환 시에도 데이터를 유지할 수 있습니다
전역적으로 접근 가능한 상태나 기능을 제공합니다
게임 매니저, 사운드 매니저 등의 관리자 클래스에 적합합니다

 

기본 구현 방법

public class GameManager : MonoBehaviour
{
    // 싱글톤 인스턴스
    private static GameManager instance;
    
    // 공개 프로퍼티
    public static GameManager Instance
    {
        get
        {
            if (instance == null)
            {
                // 씬에서 GameManager 찾기
                instance = FindObjectOfType<GameManager>();
                
                // 찾지 못했다면 새로 생성
                if (instance == null)
                {
                    GameObject go = new GameObject("GameManager");
                    instance = go.AddComponent<GameManager>();
                }
            }
            return instance;
        }
    }
    
    private void Awake()
    {
        // 인스턴스가 이미 있는지 확인
        if (instance != null && instance != this)
        {
            // 중복된 인스턴스는 제거
            Destroy(gameObject);
            return;
        }
        
        // 첫 인스턴스는 유지
        instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

 

사용 방법

// 다른 스크립트에서 GameManager 접근
public class PlayerController : MonoBehaviour
{
    void Start()
    {
        // 싱글톤 인스턴스 사용
        GameManager.Instance.StartGame();
    }
}

 

싱글톤의 주요 특징 및 장단점

장점

전역적 접근이 가능합니다
씬 전환시에도 상태를 유지합니다
인스턴스 생성을 제어할 수 있습니다

 

단점

전역 상태로 인한 의존성 문제가 발생할 수 있습니다
테스트가 어려워질 수 있습니다
남용하면 코드의 결합도가 높아질 수 있습니다

 

싱글톤 패턴을 효과적으로 사용하기 위한 팁

정말 필요한 경우에만 사용
초기화 순서에 주의
제네릭을 활용해 재사용 가능한 싱글톤 베이스 클래스를 만들 수 있음
멀티쓰레딩 환경에서는 thread-safe하게 구현해야함

 

제네릭 싱글톤 베이스 클래스 예시

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;
    private static readonly object lock_object = new object();
    private static bool applicationIsQuitting = false;

    public static T Instance
    {
        get
        {
            if (applicationIsQuitting)
            {
                return null;
            }

            lock (lock_object)
            {
                if (instance == null)
                {
                    instance = (T)FindObjectOfType(typeof(T));

                    if (instance == null)
                    {
                        GameObject singleton = new GameObject();
                        instance = singleton.AddComponent<T>();
                        singleton.name = "(singleton) " + typeof(T);
                    }
                }
                return instance;
            }
        }
    }

    protected virtual void OnDestroy()
    {
        applicationIsQuitting = true;
    }
}

 

사용방법

public class AudioManager : Singleton<AudioManager>
{
    public void PlaySound(string soundName)
    {
        // 사운드 재생 로직
    }
}

 

결론

사용해야 하는 경우

 

  • 전역적으로 하나의 인스턴스만 필요할 때 (게임 매니저, 사운드 매니저 등)
  • 공유 리소스에 대한 접근을 제어해야 할 때
  • 상태나 설정을 전역적으로 관리해야 할 때
  • 시스템 전반에 걸쳐 조율이 필요한 경우

 

주요 장점

 

  • 인스턴스의 단일성 보장
  • 전역 접근성 제공
  • 메모리 효율성
  • 초기화 지연(Lazy Initialization) 가능

 

주의 사항

 

  • 과도한 사용은 컴포넌트 간 결합도를 높임
  • 테스트가 어려워질 수 있음
  • 멀티스레드 환경에서 주의 필요
  • 객체지향 원칙을 위반할 수 있음

 

싱글톤 패턴은 전역적으로 상태를 관리하거나 리소스를 제어해야 할 때 유용하다

 

반응형