[C# Unity] 싱글턴(Singleton) 패턴

Arthur·2023년 6월 20일
0
post-thumbnail

싱글턴이란?


클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근(액세스) 지점을 제공하는 생성 디자인 패턴입니다.

*출처 : refactoring.guru(https://refactoring.guru/ko/design-patterns/singleton)

전역적으로 사용되는 객체(Object)를 매번 new 연산자로 새로운 객체를 생성하면 일관성이 깨지게 된다.
이런 객체를 전역적(static)으로 선언해주고 객체가 없을 경우 하나의 객체를 생성하고,
이미 생성된 하나의 객체만을 사용하는 패턴이다.


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


위에도 언급했듯이 객체(Object)를 최초 생성한 것을 재사용 하면서 일관성을 보장하게 해준다.
그리고 자주 호출되는 객체를 new 연산자로 매번 생성하면 메모리 누수의 문제를 방지 할 수 있다.

메모리 누수의 문제도 크겠지만 최초 생성한 동일한 객체를 사용하기 위한 이유가 더 큰 것 같습니다.


C# Unity를 공부하면서 싱글턴 패턴의 필요성을 좀 더 직관적으로 이해가 되었습니다.

주인공(스파이더맨)은 하나인데 매번 생성이 된다면 큰 문제가 될 것입니다.
그리고 생성된 주인공들의 상태를 변경 할 때도 서로 다른 값을 수정할 수 있기 때문에 문제가 발생할 수 있습니다.

첫 번째 주인공 객체에서 HP가 10이 줄어들었습니다.
두 번째 주인공 객체에서 힐링 포션을 먹어서 HP가 10 추가되었습니다.

게임에서 주인공이 분신술을 사용하지 않는 이상 발생하면 안되는 상황인 것입니다.

싱글턴 패턴의 필요성과 개념은 알았으니 이번에는 단점이 무엇이 있는지 찾아보고 고민해봤습니다.


싱글턴 패턴의 단점


  • 전역적으로 접근이 가능하기 때문에 싱글턴 객체의 변경 주체, 시점을 알기 힘들다.
  • 싱글턴 객체를 호출하는 클래스와 결합도가 높아진다.
  • 멀티 스레드 환경에서의 Race condition 문제 발생 가능성이 증가한다.
    - 이를 막이 위해 싱글톤은 mutex lock, unlock을 반복적으로 걸기 때문에 코드의 성능이 떨어지게 된다.
    • Race condition(경쟁 상태) : 둘 이상의 입력 또는 조작의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태
  • 단일 책임 원칙(Single Responsibility Principle)을 위반합니다.
    - 싱글턴은 자신의 인스턴스가 있는지 확인하고 유지되도록 하기 때문에 두 가지를 담당해 SRP를 위반합니다.
  • 너무 많은 책임을 가지거나 많은 데이터를 공유하면 클래스간 결합도가 높아져 OCP(Open Close Principle, 개발 폐쇄의 원칙)를 위반하게 됩니다.
    - OCP : 객체는 확장에 대해서는 개방적이고, 수정에 대해서는 폐쇄적이어야 한다.

싱글턴 패턴이 최초 하나의 객체만을 생성하기 때문에 성능적으로도 보장이 되는 줄 알았습니다.
단점을 공부하면서 오히려 멀티 스레드 환경이나 여러 곳에서 호출되는 싱글턴 객체는 성능 이슈를 발생할 수 있다는 것을 알게되었습니다.


싱글턴 패턴 예제 코드


namespace SingletonStudy
{
    class Player
    {
        private Player() { }


		// (1) Player 인스턴스
        private static Player instance;

		// (2) 외부에서 싱글턴 Player 객체를 Get 하는 함수
        public static Player GetInstance()
        {
            if (instance == null)
            {
                instance = new Player();
            }
            return instance;
        }
    }


    class Program
    {
        static void Main()
        { 
        	// (3) Player1과 Player2 객체에 싱글턴 Player 인스턴스 주입
            Player player1 = Player.GetInstance();
            Player player2 = Player.GetInstance();

			// (4) Player1과 Player2가 같은 객체인지 검증
            if (player1 == player2)
            {
                Console.WriteLine("player1과 player2는 같은 객체");
            }
        }
    }
}
  1. private 접근 제어자인 전역(static) Player 인스턴스
  2. GetInstance() 메서드는 싱글턴 Player 객체를 return 해주는 함수입니다.
    • Player 인스턴스가 최초로 생성되지 않았으면(null 이면) new 연산자를 사용해 새로 생성합니다.
  3. Main 메소드에서 Player1과 Player2 객체에 싱글턴 Player 인스턴스를 주입합니다.
    • new 연산자를 사용해서 새로운 객체 생성이 아닌, 최초 생성된 싱글턴 Player 인스턴스
  4. Player1과 Player2가 같은 객체인지 조건문과 비교 연산자 '==' 를 사용해 확인합니다.

위 단계를 거치면 위와 같이 Player1과 Player2가 같은 객체를 바라본 다는 것을 알 수 있습니다.

싱글턴 패턴 코드를 생성자를 사용해도 동일한 인스턴스가 생성 되도록 하는 방법도 있습니다.
하지만 간단하게 코드를 보고 이해하기 위해 위 예제코드를 가져와 봤습니다.



C# Unity 싱글턴 패턴 예제 코드


public class Managers : MonoBehaviour
{
    static Managers s_instance;
    public static Managers Instance() { init(); return s_instance; }

    // Start is called before the first frame update
    void Start()
    {
        init();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    static void init()
    {
        if (s_instance == null)
        {
            GameObject go = GameObject.Find("@Managers");
            
            // 게임 오브젝트가 null이면 @Managers GameObject 생성 및 추가
            if (go == null)
            {
                go = new GameObject { name = "@Managers" };
                go.AddComponent<Managers>();
            }

			// 게임 오브젝트가 파괴되지 않도록 설정
            DontDestroyOnLoad(go);
            
            // 게임 오브젝트의 Managers 컴포넌트를 인스턴스에 추가
            s_instance = go.AddComponent<Managers>();
        }
    }
}

위 예제 코드는 인프런 'C#과 유니티로 만드는 MMORPG 게임 개발 시리즈' 강의 코드를 가져온 것입니다.
구조는 어느정도 비슷하지만, C# 유니티에서는 GameObject 클래스를 사용해서 싱글턴 패턴을 구현합니다.

아직 강의에 초입 부분이라 싱글턴 게임 오브젝트를 제대로 활용해 보지는 못했습니다.
하지만 개념을 어느정도 잡고 가야 할 것 같아서 이렇게 작성해봤습니다.

다양한 레퍼런스를 읽고 정리하면서 싱글턴의 개념, 사용 이유, 단점들을 알게 되었습니다.



참고 자료


  • 인프런 - [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 => 링크
  • Refactoring Guru - 싱글턴 패턴 => 링크
  • 공부하는 식빵맘 - Chapter 2. 싱글톤 패턴(Sigleton Pattern) => 링크
  • 위키백과 - 싱글턴 패턴 => 링크
profile
기술에 대한 고민과 배운 것을 회고하는 게임 서버 개발자의 블로그입니다.

0개의 댓글