내일배움캠프 6주차 2일차 TIL - 싱글턴

백흰범·2024년 5월 21일
0
post-thumbnail

오늘 한 일

  • 챌린지반 과제 풀이 (제너릭 싱글턴 구현하기)
  • 팀 프로젝트 진행 (오브젝트 풀링, 파워업 추가)
  • 챌린지반 특강 듣기 (Delegate, event, UnityAction)
  • 여태까지 배운 내용 시험 풀기

오늘은 선언해두면 언제 어디서든 접근이 가능한 싱글턴 패턴에 대해서 알아보자


싱글턴

기초 개념

싱글턴은 클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근 지점을 제공하는 생성 디자인 패턴입니다. 리팩토링 구루

  • 모든 인스턴스들이 싱글턴 패턴에게 접근이 가능하다.



기초 구현

싱글턴을 선언할 때 가장 중요한 키워드에 대해서 설명해주겠다.

static (정적 선언)

  • 인스턴스가 아닌 클래스에 속하는 정적 멤버를 선언할 때 사용하는 키워드입니다.
  • 클래스, 인터페이스 및 구조체에서 필드, 메서드, 속성, 연산자, 이벤트 및 생성자에 static 키워드를 추가할 수 있습니다
  • static 한정자는 인덱서 또는 종료자와 함께 사용할 수 없습니다.
public class Class1
{
	public static int staticField = 2;
   
    public static void staticMethod()
    {
    	Console.WriteLine("저는 정적 메서드입니다. 바로 외부에서 호출이 가능합니다.");
    }
}

// 호출 해보기
static void Main(string[] args)
{
    Console.WriteLine(Class1.staticField);
    Class1.staticMethod();
}
  • 정적 선언한 필드와 메서드들은 인스턴스 선언 없이 바로 외부로 호출이 가능하다.


% static 사용 시 주의사항 %

1. static이 아닌 멤버에서는 static 멤버를 사용 가능하지만 static인 멤버에서 static이 아닌 멤버를 사용할 수 없다

(사용하려면 인스턴스 생성을 해줘야한다)

  • 그래서 위와 동일한 이유로 Progam 클래스에 선언했다고 해서 Main 함수에서 사용이 불가능한 이유와 동일하다.

2. static 멤버는 인스턴스 단위로 참조가 불가능하다.

  • static은 아예 클래스 소속이기 때문에 클래스 자체로 불러줘야한다.

static은 아예 클래스 자체에 속하기 때문에 이 점을 이용해서 싱글턴을 만들어내는 것이다.



static을 활용해 싱글턴 선언하기

유니티에서 가장 기초적인 싱글턴

public class GameManager : MonoBehaviour
{
	public static GameManager instance;
	void Awake()
    {
    	instance = this; // this는 클래스의 현재 인스턴스를 가리킨다.
    }
}

VisualStudio에서 기초적인 싱글턴

public class GameManager
{
    public static GameManager instance = new GameManager(); // Awake 같은 건 없으니 이로 대체해주자.

    public int field = 1;
}

// 사용해보기
static void Main(string[] args)
{
    GameManager.instance.field = 4;
    Console.WriteLine(GameManager.instance.field);
}
  • 숫자가 잘 변경되고 호출된 모습을 볼 수 있다.

  • 해당 코드들을 잘 보면 static을 이용해 클래스 소속 클래스타입 멤버를 선언해서 거기에 자기 자신을 할당하는 방식이다.

이것도 싱글턴 패턴인가요?

    static class staticClass
    {
        public static int staticField = 4;

        public static void staticMethod()
        {
            Console.WriteLine("정적 클래스의 정적 메서드입니다.");
        }
    }
  • 물론 싱글톤과 비슷하게 static 필드를 바꿀 수 있고 메서드도 호출 가능하지만, 싱글턴에 비해서 제한적인 사항이 많다.
  1. 정적 멤버만 선언 가능
  2. 인터페이스 구현 불능
  3. 상속과 재정의 불능
  • 정적 클래스는 단순히 서로 연관된 메서드를 묶어두는 것에만 가깝기 때문에 절차적 프로그래밍에 가깝다고 본다.
  • 해당 코드의 사용처는 주로 유틸리티 클래스, 수학 함수 등에서 사용된다.

싱글턴 사용 시 주의할 점

싱글턴의 편의성 때문에 사용에 주의해야 한다.

1. 싱글턴 클래스가 많은 책임과 기능 짊어질 수도 있다.

  • 가능하다면 최대한 여러 클래스로 분담해주는 것이 좋다.
    (의존도와 결합도에 유의해줘야한다.)

2. 객체 생성 시기를 제어할 수 없다.

  • 그래서 주로 항상 상주해야만 하는 GameManager나 AudioManager과 같은 곳에 싱글톤을 사용하는 편이다.

3. 유니티에서는 겹쳐서 생성되는 경우를 주의해야한다.

  • if (instance == null)을 통해 클래스의 instance가 겹치지 않게 유의해줘야한다.

유니티에서 싱글턴 패턴 구현하기

현재 사용하는 싱글턴

public class SystemManager : MonoBehaviour
{
    public static SystemManager instance;

    void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(instance); // 씬이 넘어가도 파괴되지 않게하기
        }
        else
        {
            Destroy(gameObject); // 겹치는 건 파괴
        }

제너릭 싱글턴(오브젝트 탐색)

코드 출처 - 실리의 프로그램 사이트

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

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                GameObject obj;
                obj = GameObject.Find(typeof(T).Name);
                if (obj == null)
                {
                    obj = new GameObject(typeof(T).Name);
                    instance = obj.AddComponent<T>();
                }
                else
                {
                    instance = obj.GetComponent<T>();
                }
            }
            return instance;
        }
    }

    public void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}
  • 해당 제너릭 싱글턴은 오브젝트를 기준으로 찾아내기 때문에 해당 싱글턴을 상속받은 클래스와 오브젝트의 이름이 동일해야한다.


참고 자료

리팩토링 구루 - 싱글톤 패턴

Learn.Microsoft - static 한정자

실리의 프로그램 사이트 - Unity Singleton을 제네릭으로 만들어놓고 써봅시다




작성하면서 느낀점

기존에 알고 있음에도 불구하고 다시 써보고 정리해보니 전보다 이해가 깊이 되고 좀 더 발전된 방식의 싱글톤 사용이 가능해졌다. 기존 지식을 회고하는 것만으로도 코드 기획에 많은 도움이 되는 것 같다.

profile
게임 개발 꿈나무

0개의 댓글