유니티

Managers 클래스와 싱글톤(Singleton) 패턴

코다람쥐 2022. 2. 1. 20:07

 

1. 정의

싱글톤 패턴은 어떤 객체의 인스턴스가 단 1개만 존재할 때 사용하는 패턴이다.

static을 사용하며 구현하면 된다.

특징으로는 유일성이 보장된다.

 

2. 매니저 클래스

유니티에서 게임을 관리하는 매니저 역할을 하는 클래스를 정의하면 게임의 관리가 쉬워진다.

설계적인 부분에서 매니저 클래스는 1개만이 존재해도 되기 때문에 싱글톤 패턴으로 정의하면 쉽다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers Instance;
    public static Managers GetInstance() { return Instance; }
    // Start is called before the first frame update
    void Start()
    {
        GameObject go = GameObject.Find("Manager");
        Instance = go.GetComponent<Managers>();
    }
}

static으로 자료형이 Managers이고 변수명이 Instance인 객체를 하나 생성하였다.

이 객체는 GetInstance메소드를 통해서만 호출이 가능하게 캡슐화를 하였다.

 

Start() 메소드에서 하이라키에 Manager라는 객체가 있는지 찾아서 go객체에 반환하였다.

그리소 Instance객체에 Managers컴포넌트를 넣어주었다.

이렇게 하는 이유는 Manager객체를 복사하여 Manager (1), Manager (2), Manager (3)을 실수로 생성하더라도 

진짜는 "Manager"라는 이름을 가진 객체가 되기 때문에 "Manaer (1), (2), (3)"이름의 객체들은 무시하게 된다.

 

그런데 위와같이 선언하면 한 가지 문제점이 생긴다

프로그래머가 실수로 "Manger"라는 이름의 객체를 정의하지 않게되었을 때 문제가 생긴다.

존재하지 않는 객체를 참조하려고하면 오류가 발생할 것이다.

 

그래서 위의 코드를 아래와 같이 다듬어주면된다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Managers : MonoBehaviour
{
    static Managers Instance;
    public static Managers GetInstance() { Init(); return Instance; }
    
    void Start()
    {
        Init();
    }
    static void Init()
    {
        if (Instance == null)
        {
            GameObject go = GameObject.Find("Manager");
            if (go == null)
            {
                go = new GameObject { name = "Manager" };
                go.AddComponent<Managers>();
            }

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

만약 Manager라는 객체가 존재하지 않는다면 GamaObject.Find("Manager");이 실행될 때 null값이 반환이 된다.

그러면 Manager라는 이름의 객체가 만들어지고

Mangers라는 컴포넌트가 스스로 추가된다. 

GetInstance(); 메소드에도 Init()함수를 넣어서 매니저가 호출이되면 Init()함수가 실행되게 하였다.

(참고로 GetInstance()메소드는 프로퍼티로 선언해도 상관없다.)

 

 

다른 객체에서 Manager클래스에 접근할 때는 아래와 같이 접근하면 된다.

public class Player : MonoBehaviour
{
    Managers ma = Managers.GetInstance(); 
}

GetInstance()를 통해 Managers.Instance에 접근하였다.

이제 Player클래스에서는 ma를 통해 매니저 클래스에 언제든지 접근할 수 있게되었다.