사전캠프/Unity

디자인 패턴 - 싱글톤 패턴

서보훈 2024. 8. 20. 17:47

강의 진행중, GameManager를 싱글톤 처리를 하는것을 볼 수 있을것입니다.

 

이 싱글톤 패턴은 무엇인지, 왜 사용하는지를 정리해보겠습니다.


싱글톤 패턴과, 다른 디자인 패턴들에 관해 설명하는 웹 페이지 링크입니다

https://refactoring.guru/ko/design-patterns/singleton

 

싱글턴 패턴

/ 디자인 패턴들 / 생성 패턴 싱글턴 패턴 다음 이름으로도 불립니다: Singleton 의도 싱글턴은 클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근​(액세스) 지점을 제공하

refactoring.guru


일단 싱글톤 패턴을 사용하는 이유는 단 하나만 존재해야하는 데이터를 다양한 위치에서 사용하는 경우 유용하게 사용할 수 있기 때문입니다.

 

기본적으로 싱글톤 패턴을 사용하는 클래스는 static을 사용해 자신의 접근지점을 정적으로 선언합니다.

즉, Unity의 경우 싱글톤 패턴으로 만들어진 클래스에 접근하기 위해 GetComponent를 사용하거나, public 을 사용해 해당 스크립트를 끌어올 필요가 없이 Instance를 사용해 해당 클래스의 함수를 사용할 수 있게됩니다.

 

또한 해당 데이터가 단 하나만이 존재함을 확실히 할 수 있습니다.

만약 플레이어의 소지금을 관리하는 변수가 있을때, 해당 변수는 게임에서 무조건 하나만 존재해야합니다.

이러한 변수를 싱글톤으로 선언한 클래스에 만들어서 관리하면, 이 데이터가 여러개 존재할 일이 없음을 확신할 수 있습니다.

 

이러한 특성 때문에 GameManager같은 게임을 관리하는 클래스를 싱글톤패턴으로 만들게 됩니다.

게임 전체를 관리하기 때문에 단 하나만 존재하야하며, 다른 클래스들이 이 클래스에 접근해서 데이터를 확인해야하기 때문입니다.

 

실제 싱글톤 패턴의 형태를 보도록 하겠습니다.

해당 코드의 경우 싱글톤 패턴으로 만들고 싶은 클래스가 이 코드를 상속받아서 싱글톤 패턴이 적용된 코드가 되도록 해줍니다.

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    private static T instance;
    public static T Instance { get { return instance; } }
    public static bool InstanceExist { get { return instance != null; } }

    protected virtual void Awake()
    {
        if(InstanceExist)
        {
            Destroy(gameObject);
            return;
        }
        instance = (T)this;
    }

    protected virtual void OnDestroy()
    {
        if (instance == this)
        {
            instance = null;
        }
    }
}

 

첫번째줄의 Singleton<T> 의 경우 제네릭 클래스를 뜻하는것으로, T 에 사용될 변수 선언을 해당 클래스를 상속받는 클래스의 이름이 되도록 합니다.

 

첫번째 줄에서 private 으로 인스턴스를 선언하고, 이 인스턴스에 대한 접근 지점을 두번째줄에서 속성의 형태로 만들어줍니다.

이를통해 다른 클래스에서 이 클래스를 읽어들일수는 있지만, 인스턴스를 변조할 수 없도록 만듭니다.

세번째줄에서는 이 클래스가 단 하나만 존재할 수 있도록 만들어줍니다. 만약 이 싱글톤 인스턴스가 있다면

 instance != null 값이 true가 되어 다음 인스턴스를 생성하려고 할 때 if문이 작동하여 새로 생성된 싱글톤을 파괴하게 됩니다.

 

Awake문 에서는 이 클래스가 생성될 때, 이미 이 클래스가 있는지를 확인하고 있으면 스스로를 파괴, 없으면 인스턴스를 자신으로 지정합니다.

해당 코드는 상속받는것을 가정하고 있기 때문에 Awake가 protected virtual 로 선언되어있고, 인스턴스를 상속받은 클래스로 지정합니다.

 

OnDestroy문 또한 상속을 전제로 만들어졌기 때문에 protected virtual로 선언되어있습니다.

또한 여기서는 이 클래스가 파괴될때, 인스턴스를 null로 초기화 시켜주는 역할을 해서 다시 이 클래스를 사용할때 싱글톤이 정상적으로 생성되도록 만들어줍니다.