전체 코드

1. 싱글턴 패턴이란?

싱글턴(Singleton) 패턴의 개념

  • 싱글턴 패턴은 객체를 하나만 생성하고, 이를 전역적으로 접근할 수 있도록 보장하는 디자인 패턴이다.
  • 전역적으로 하나의 인스턴스를 공유하며, 여러 곳에서 동일한 인스턴스를 참조할 수 있도록 한다.

싱글턴 패턴을 사용하는 이유

  1. 유일성 보장:
    • 특정 객체가 프로그램 내에서 단 하나만 존재하도록 한다.
    • 예: 게임 매니저, 네트워크 매니저, 설정 관리자 등.
  2. 일관성 유지:
    • 여러 개의 인스턴스가 생성될 경우 데이터가 일관되지 않을 위험이 있음.
    • 싱글턴을 사용하면 같은 객체를 공유하므로 데이터의 일관성을 유지할 수 있음.
  3. 메모리 절약:
    • 동일한 인스턴스를 여러 개 생성하지 않기 때문에 불필요한 메모리 사용을 방지할 수 있음.
  4. 어디서든 접근 가능:
    • 전역 접근이 가능하여 편리한 데이터 공유 및 관리가 가능함.

2. 싱글턴을 활용한 게임 매니저 구현

게임 매니저의 역할

  • 게임 전체를 관리하는 중앙 관리 시스템.
  • Managers 클래스를 싱글턴 패턴으로 만들어 전역적으로 관리할 수 있도록 함.

3. 게임 매니저 오브젝트 가져오기

GameObject obj = GameObject.Find("@Managers");
Managers mag = obj.GetComponent<Managers>();
  • 코드 설명:
    • GameObject.Find("@Managers")
      • 현재 씬(Scene) 에 존재하는 오브젝트 중에서 이름이 "@Managers"인 오브젝트를 찾는다.
      • 단, 활성화(Active)된 오브젝트만 찾을 수 있다.
    • obj.GetComponent<Managers>()
      • "@Managers" 오브젝트에 붙어 있는 Managers 스크립트를 가져와 mag 변수에 저장한다.

문제점

  1. "@Managers" 오브젝트가 없는 경우 → null 반환
  2. "@Managers" 오브젝트는 있지만 Managers 컴포넌트가 없는 경우 → null 반환

4. 싱글턴 구현 방법

첫 번째 방법: 기본적인 싱글턴 구현

public class Managers : MonoBehaviour
{
    static Managers Instance;  // 유일성이 보장된다.

    public static Managers GetInstance()
    {
        return Instance;  // 유일한 매니저를 반환
    }

    void Start()
    {
        GameObject obj = GameObject.Find("@Managers");
        Instance = obj.GetComponent<Managers>();  // Instance에 스크립트를 할당
    }
}

설명

  • static Managers Instance
    • 정적(static) 변수로 선언하여 단 하나의 인스턴스만 유지하도록 함.
  • GetInstance()
    • 현재 Instance를 반환하는 정적 메서드로 다른 곳에서 Managers.GetInstance()로 접근 가능.
  • Start()
    • 현재 씬에서 "@Managers" 오브젝트를 찾아 Managers 컴포넌트를 Instance에 저장.

문제점

  • "@Managers" 오브젝트가 없으면 Find 함수가 null을 반환하여 오류 발생 가능.
  • "@Managers" 오브젝트에 Managers 스크립트가 없으면 null이 되어 참조 오류 발생.

5. 개선된 싱글턴 구현

두 번째 방법: 오브젝트가 없을 경우 자동 생성

public class Managers : MonoBehaviour
{
    static Managers Instance;

    public static Managers GetInstance()
    {
        Init();
        return Instance;
    }

    void Start()
    {
        Init();
    }

    static void Init()
    {
        if (Instance == null)
        {
            GameObject obj = GameObject.Find("@Managers");

            if (obj == null)
            {
                obj = new GameObject { name = "@Managers" };
                obj.AddComponent<Managers>();
            }

            DontDestroyOnLoad(obj);
            Instance = obj.GetComponent<Managers>();
        }
    }
}

개선 사항

  1. Init() 메서드를 추가하여 초기화 과정을 한 곳에서 관리하도록 함.
  2. Instance == null 인 경우에만 오브젝트를 찾거나 생성하여 불필요한 Find() 호출을 줄임.
  3. "@Managers" 오브젝트가 없으면 자동으로 생성하여 안정성을 높임.
  4. DontDestroyOnLoad(obj) 를 사용하여 씬이 변경되어도 유지되도록 설정.

6. 프로퍼티를 활용한 싱글턴 구현

세 번째 방법: GetInstance() 대신 프로퍼티 사용

public class Managers : MonoBehaviour
{
    static Managers s_instance;

    public static Managers Instance
    {
        get
        {
            Init();
            return s_instance;
        }
    }

    static void Init()
    {
        if (s_instance == null)
        {
            GameObject obj = GameObject.Find("@Managers");

            if (obj == null)
            {
                obj = new GameObject { name = "@Managers" };
                obj.AddComponent<Managers>();
            }

            DontDestroyOnLoad(obj);
            s_instance = obj.GetComponent<Managers>();
        }
    }
}

설명

  • GetInstance() 메서드를 사용하지 않고 프로퍼티(Instance)로 대체.
  • Instance 프로퍼티를 호출하면 자동으로 Init()을 실행하여 초기화 진행.
  • Managers.Instance 로 간단하게 접근 가능.

장점

  • 코드가 더 직관적이고 가독성이 좋아짐.
  • Instance 프로퍼티를 호출할 때만 초기화가 실행됨.

7. 싱글턴 패턴의 장점과 단점

장점

  1. 유일성 보장
    • 객체가 한 개만 생성되므로 데이터의 일관성이 유지됨.
  2. 전역 접근 가능
    • Managers.Instance 로 어디서든 간편하게 접근할 수 있음.
  3. 메모리 절약
    • 동일한 객체를 여러 개 생성하는 것이 아니라 하나의 인스턴스를 재사용함.

단점

  1. 전역 접근의 위험
    • 프로그램 전체에서 접근 가능하므로 잘못된 사용으로 인해 버그가 발생할 위험이 있음.
  2. 결합도 증가
    • 다른 클래스에서 Managers.Instance를 직접 참조하면 의존성이 증가하여 유지보수가 어려워질 수 있음.
  3. 멀티스레드 환경에서 문제 발생 가능
    • 멀티스레드 환경에서 Instance가 동시에 초기화되면 Race Condition(경쟁 상태) 문제 발생 가능.
    • 이를 방지하려면 스레드 동기화 (lock 사용) 을 추가해야 함.

profile
李家네_공부방

0개의 댓글