[Unity] 유니티 싱글턴 패턴 구현 1 ( Singleton Pattern )

TNT·2023년 11월 10일
0

유니티 디자인패턴

목록 보기
2/14

싱글턴 패턴

유니티 디자인 패턴 중에서 제일 유명한 게 싱글턴 패턴이다.
가장 쉽게 배울 수 있고 복잡한 문제를 빠르게 수정 가능도 한데
인터넷에서 찾아보면 또 사람들이 은근히 꺼려하는 부분이 있다고 쓰지 말라고 하는 사람도 있다.

싱글턴 패턴은 개별 매니저 클래스에서 게임에 시스템을 관리한다.

또한 매니저가 게임 내부에 있는 복잡한 구성을 숨기고 앞에서 관리하기 때문에 좋아 보이지만
싱글턴 패턴은 핵심 구성 요소 간에 강력한 결합으로 개별 유닛 테스트가 힘들어지는 단점이 존재한다.

1.싱글턴 패턴 기본

싱글턴에 중요한 목적은 유일성의 보장이다.

싱글턴 패턴을 제대로 구현했다면 초기화된 이후에는 런타임 도는 동안 메모리에 하나의 인스턴스만 존재해야 한다.

싱글턴 패턴에서 중요한 건 구현을 잘됐다면 하나만 존재한다 그렇지 않다면 싱글턴 패턴에 실패한 것이다.

기본적으로 싱클턴 패턴의 동작
보면 기본적으로 클라이언트 클래스에서 싱글턴 객체한테 요청 보내고 받는게 전부이다.

2. 싱글턴 패턴 장단점

싱글턴 패턴의 장점

전역 접근 가능: 싱글턴 패턴을 사용해서 리소스나 서비스의 전역에서 접근점을 만들 수 있다.
동시성 제어: 공유 자원의 동시에 접근을 제한이 가능하다.

싱글턴 패턴의 단점

유닛 테스트: 싱글턴 패턴을 남발하면 개당 유닛단위 테스트가 어려워진다. 싱글턴 오브젝트가 또 다른 싱글턴 패턴에 종속이 될 수도 있다. 그 많은 패턴에 하나가 누락되면 종속성이 끊어지고 테스트가 불가능 해진다.

이런 문제는 퍼사드와 싱글턴을 조합해서 핵심 시스템에 대한 전면 인터페이스를 설정할 때 자주 발생 되는 문제이다.
결국엔 필요할 때 유닛만 가지고 가서 따로 테스트를 못하고 디버그 하는 것이 불가능해진다.

잘못된 습관: 싱글턴 패턴이 쉽고 코드에 딱히 크게 관여 안 해도 버그 없이 돌아가기 때문에 코드 작성 할 때 정교하게 접근하기보단 그냥 싱글턴으로 불러서 처리하게 된다고 위험하다.

다른 이야기로 디자인 패턴을 선택할 때 아키텍처의 유지 및 관리, 확장, 테스트 가능 여부를 생각해둬야 한다.

구현할 패턴의 구조
이번 글에서는 하나의 클래스를 그대로 싱글턴으로 쓰는경우도있지만
여기에서는 부모클래스로 두고 받아와서 구현하는 방식으로 구현했다.

3.유니티에서 사용

유니티 프로젝트에서 자주 보는 표준 클래스가 바로 게임 매니저이다.

물론 개발자마다 구현하는 범위도 다른 사용하는 상태도 다르지만 일단 핵심 게임 시스템의 인터페이스로 싱글턴을 사용한다.

일단 처음으로 유니티에서 Singleton 클래스를 만들어보자

using UnityEngine;

public class Singleton < T > : MonoBehaviour where T : Component
{
    private static T _instance;

    public static T Instance
    {
        get
        {
            if(_instance == null)
            {
                _instance = FindObjectOfType<T>();

                if (_instance == null)
                {
                    GameObject obj = new GameObject();
                    obj.name = typeof(T).Name;
                    _instance = obj.AddComponent<T>();
                }
            }

            return _instance;
        }
    }

    public virtual void Awake ()
    {
        if(_instance == null)
        {
            _instance = this as T;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

싱글턴 Singleton T 첫 부분에서 보면 get 접근자로 public static 속성으로 설정해 주고 구현했다.
먼저 생성하기 전에 이전에 다른 인스턴스가 없는지

_instance = FindObjectOfType T(); 찾아보고 없으면 지정된 타입이 없으면 새로운 GameObject를 생성하고
이름을 지정한 후에 컴포넌트 추가하고 만들어준 뒤 리턴 해준다.

마지막 부분에 Awake() 함수를 보면 일단 자식 클래스에서 변형으로 사용할 수 있게 가정하고 virtual로 지정해 주고

엔진에서 Awake() 함수를 호출했을 때 싱글턴 컴포넌트가 메모리에 초기화된 자신이 있는지 체크하고 없으면 생성하고

있으면 지워 버린다.

그래서 메모리 내에서 자신 타입만 존재하게 된다.

여기서 DontDestroyOnLoad(gameObject); 부분을 보게 되면 씬이 넘어가거나 새로운 씬으로 도착했을 때 기존 씬에 있는 애들은 지워지지만 위 함수로 설정하게 된다고 지워지지 않고 씬변환이 있더라고 유지된다.

이러한 기능으로 싱글턴 패턴에 유용하게 사용된다.

여기서 중요 한건 맨위 클래스 선언때
public class Singleton < T > : MonoBehaviour where T : Component
의미를 모르겠다면 한번 공부 하고 다시 보는걸 추천합니다.

이제 GameManager 클래스를 생성하고 Singleton 클래스를 부모 클래스로 받아보자.

public class GameManager : Singleton<GameManager>
    {
        private DateTime _sessionStartTime;
        private DateTime _sessionEndTime;

        private void Start()
        {
            _sessionStartTime = DateTime.Now;
            Debug.Log($"Game Scenes Start {DateTime.Now}");
        }

        private void OnApplicationQuit()
        {
            _sessionEndTime = DateTime.Now;

            TimeSpan timeDifference = _sessionEndTime.Subtract( _sessionStartTime );

            Debug.Log($"Game Session Ended {DateTime.Now}");
            Debug.Log($"Game Session Lasted {timeDifference}");
        }

        private void OnGUI()
        {
            if(GUILayout.Button("Next Scene"))
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
            }
        }

    }

OnGUI로 임시 버튼을 만들고 Scene 교체하는 동작만 들어가있다.

신을 여러 개 만들어주고
그 후 File Build Settings에서 Init 신을 0번 인덱스로 지정해 준다.

그후 오브젝트 넣고 스크립트 넣어서 보면 잘 동작하는걸 확인할수있다.

이제 여기에 클래스 안에 이제 다른 클래스에서 데이터나 자료 등등 요청을 하게 된다면 전역으로 접근이 가능하기 때문에

활용도가 매우 높다고 생각한다.
하지만 지나친 사용은 의존성이 너무 높아지기 때문에 적절하게 잘 사용하도록 하자.
내가 활용한다고 한다면

대화 데이터, 유닛 데이터, 이미지 데이터, 유저 데이터, 사운드 데이터, 이런 것들을 매니저를 각각 나눠서 저장하고 사용할 거 같다.

여기까지가 이론 겸 기능만 만들었고 그러면 2번째에선 어떤방식으로 동작하고 응용하는지 서술 라겠다

참조

유니티 디자인패턴 책

profile
개발

0개의 댓글