Unity 개발일지

[Unity] Generic Singleton(제네릭 싱글톤) 본문

Unity 개발

[Unity] Generic Singleton(제네릭 싱글톤)

아머르 2024. 6. 13. 20:32

이제 싱글톤은 익숙하다! 싶은 분들을 위해 준비했습니다. 제네릭 싱글톤!

 

일반적인 싱글톤 패턴은 특정 클래스의 인스턴스가 하나만 존재하도록 보장하고, 어디서든 그 인스턴스에 접근할 수 있도록 하는 디자인 패턴이다. 싱글톤 패턴은 전역 변수와 유사하지만, 싱글톤 인스턴스는 다른 코드에 의해 덮어쓰지 못하도록 보호된다.

Generic Singleton !!!

제네릭이란 C++ 을 공부했던 사람들은 잘 아는 템플릿과 비슷한 개념이다.

제네릭 싱글톤은 일반적인 싱글톤 패턴의 개념을 확장하여 다양한 유형의 객체를 관리할 수 있도록 한다.

즉, 제네릭 싱글톤 클래스를 정의할 때 특정 유형의 객체를 지정하고, 이 클래스를 통해 해당 유형의 유일한 인스턴스를 생성하고 접근할 수 있습니다.

유니티에서 제네릭 싱글톤은 특정 유형의 객체를 하나만 인스턴스화하고 어디서든 접근할 수 있도록 하는 디자인 패턴으로 일반적인 싱글톤 패턴과 유사하지만, 제네릭 싱글톤은 다양한 유형의 객체를 관리할 수 있다는 장점이 있습니다.

 

 

[제네릭 싱글톤의 장점]

코드 간결성

여러 싱글톤 클래스를 각각 작성할 필요 없이 하나의 제네릭 싱글톤 클래스만 작성하면 된다.

 

유형 안전성 향상

특정 클래스에 종속되지 않고, 여러 타입을 제네릭 인자로 받아들일 수 있어 유연하다.

 

코드 재사용성 향상

하나의 제네릭 싱글톤 클래스를 작성하면 다양한 타입에 대한 싱글톤 패턴을 쉽게 구현할 수 있다. 코드 중복을 줄이고 재사용성을 높일 수 있다.

 

메모리 효율성 향상

제네릭 싱글톤은 특정 유형의 객체에 대해 하나의 인스턴스만 제공하기 때문에 메모리 사용량을 줄일 수 있습니다.

 

 

[제네릭 싱글톤의 단점]

타입 안전성 부족

잘못된 타입을 전달할 경우 런타임 에러가 발생할 수 있다. 제네릭 타입에 대한 제약 조건을 설정하지 않으면 타입 안전성을 보장하기 어렵다.

 

초기화 지연

처음으로 접근할 때 인스턴스가 생성되므로, 첫 접근 시 약간의 지연이 발생할 수 있다.

 

메모리 관리

DonDestroyOnLoad를 통해 씬 전환 시에도 인스턴스를 유지할 수 있지만, 이를 잘못 관리하면 메모리 누수 문제를 일으킬 수 있다.

 

 

 

 

[제네릭 싱글톤의 구현]

1. 제네릭 MonoBehaviour 클래스 정의: T 라는 제네릭 매개 변수를 사용하여 MonoBehaviour 클래스를 정의한다.

 

2. 생성자 정의: 생성자를 protected로 선언하여  외부에서 인스턴스를 직접 생성하지 못하도록 한다.

 

3. getInstance() 메서드 정의: 이 메서드는 다음과 같은 작업을 수행한다.

 - 싱글톤 인스턴스가 아직 존재하지 않으면 새 인스턴스를 생성하고, DonDestroyOnLoad를 사용하여 장면전환시에도

   파괴되지 않도록 한다.

 - 싱글톤 인스턴스가 이미 존재하면 기존 인스턴스를 반환한다.

 

4. 인스턴스 변수: 싱글톤 인스턴스를 저장하기 위한 변수를 정의한다.

 

<GenericSingleton 코드 예시>

이 코드를 아카이빙 해놓고 우려먹자!

 

<코드설명>

GenericSingleton<T>라는 제네릭 클래스 선언. 'T' 는 타입 파라미터

where T : MonoBehaviour: 제네릭 타입 T는 반드시 MonoBehaviour를 상속받는 클래스여야 합니다.

이를 통해 T는 Unity 오브젝트로 사용할 수 있습니다.

 

싱글톤 인스턴스를 저장, static으로 선언되어 클래스 래벨에서 하나만 존재한다.

 

 

이 프로퍼티는 싱글톤 인스턴스를 반환한다. 만약 인스턴스가 아직 생성되지 않았다면, 인스턴스를 생성한다.

 

if (_instance == null)

현재 _instance가 null인지 확인한다.

 

FindObjectOfType<T>()

씬에 있는 T 타입의 오브젝트를 찾고, 없으면 null을 반환한다.

만약 찾지 못했다면 새로운 게임 오브젝트를 생성하고, 여기에 T 타입의 컴포넌트를 추가한다.

 

상속받는 클래스에서 구현하도록 protected virtual 로 Awake문을 만들어준다.

그리고 _instance가 null 이면 해당 스크립트를 가진 오브젝트를 등록해주고, 씬이동간 파괴되지 않도록 해준다.

 

[사용 예시]

일단 사용하기 위해서는 위의 GenericSingleton<T> 클래스를 만들어야한다.

점수를 늘려주는 함수를 가진 GameManager 함수를 만들어주었다.

해당 스크립트를 빈 오브젝트(이름이 GameManager인)에 등록하고 사용하면 끝!

 

 

[제네릭 싱글톤 사용 시 주의 사항]

 

멀티스레딩 문제:

멀티스레딩 환경에서 제네릭 싱글톤을 사용할 경우, 동기화 문제로 인해 여러 인스턴스가 생성될 수 있다. 이를 방지하려면 lock 키워드를 사용하여 스레드 안전성을 보장해야 한다.

 

메모리 누수:

DontDestroyOnLoad를 사용할 경우, 필요하지 않은 씬 전환 시에도 오브젝트가 메모리에 남아 있을 수 있습니다. 메모리 관리에 주의해야 한다.

 

인스턴스 초기화:

제네릭 싱글톤 클래스 내부에서 인스턴스를 초기화하는 과정에서 예외가 발생할 수 있다. 이 경우, 적절한 예외 처리를 통해 문제가 발생하지 않도록 해야 한다.

 

제네릭 제약 조건:

제네릭 타입에 대해 적절한 제약 조건을 설정하여 올바른 타입만 사용할 수 있도록 해야 한다. 예를 들어,

where T : MonoBehaviour와 같이 제약 조건을 설정하면 잘못된 타입 사용을 방지할 수 있다.

 

반응형