티스토리 뷰
본 블로그에서는 제너릭과 싱글톤을 모두 다뤄본 적이 있다.
제너릭: https://lsu0503.tistory.com/61
Today I Learned - Day 12 [제너릭]
오늘은 제너릭에 대해서 정리해 볼 까 합니다.사실은 개략적으로는 알고있었지만, 안쓴 지가 꽤 되다 보니 가물가물해서...이번 프로젝트에 쓰이기도 했고 해서 정리를 해 보려고 합니다. 제너
lsu0503.tistory.com
싱글톤: https://lsu0503.tistory.com/47
Today I Learned - Day 5 [싱글톤]
싱글톤싱글톤 자체는 본 캠프를 시작하자 마자 다루기 시작한 요소이긴 하나, 이번에는 이러한 싱글톤의 특징에 대해서 다뤄보려고 한다. MonoBehaviourMonoBehaviour에서 싱글톤을 생성하기 위해서는
lsu0503.tistory.com
이번에는 이 둘을 조합하여 생각해 보자.
제너릭의 강점은 '범용성'이다. 이를 이용해서 다양한 형식을 아울러서 지원할 수 있는 코드를 작성할 수 있고, 이를 통해서 전체적으로 정돈된 코드를 지향할 수 있다.
그러니까, 구현했던 요소를 변수형이 달라졌다고 새로 작성할 필요가 없다는 뜻이다.
싱글톤의 강점은 '유용성'이다. 이를 이용해서 다양한 객체에서 요소를 아울러서 지원할 수 있는 코드를 작성할 수 있고, 이를 통해서 정동된 코드를 지향할 수 있다.
그러니까, 의존성을 싱글톤 하나를 향하도록 구성할 수 있다는 것이다. 안좋을 거 같지만, 싱글톤에 담긴 내용을 조절하면 오히려 의존성을 낮출 수 있는 묘안으로 작동한다.
그렇다면 '제너릭 싱글톤은 범용성 높고 유용성도 높겠구나!' 하고 생각할 수도 있다.
사실 엄밀히 말하면 아니다. 제너릭 싱글톤은 그저 '싱글톤의 제작을 제너릭으로 구현할 뿐'인 내용이다.
다만, 싱글톤 자체는 게임에 적어도 1개는 있고, 많으면 얼마나 많을지 감이 안오는 요소이기 때문에, 그 범용성을 최대한으로 활용할 수 있는 기법 중에 하나이긴 하다.
그러므로, 제너릭의 활용 방법을 마음에 새기면서, 제너릭 싱글톤의 사용법을 알아보자.
기본 형태
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
private void Awake
{
get
{
if (instance == null)
instance = this;
else
Destroy(gameObject);
return instance;
}
}
}
잘 보면 일반적인 싱글톤이랑 비교하면 instance가 T로 구현되어 있을 뿐, 그다지 큰 차이는 없다.
다만, 이것 만으로도 큰 것이, 이후에 이 클래스를 상속받은 다른 클래스를 사용한다면 이러한 싱글통 구성이 자동으로 구현되게 된다.
다만, 여기 까지만 진행하면 다소 아쉬우니까, 여기에 어제 작성했던 AddComponent와 결합해 보자.
using Unity.VisualScripting;
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
// instance가 지정이 되어있지 않다면
if (instance == null)
{
GameObject singletonObj;
// 씬에 이미 목표 컴포넌트가 담긴 인스턴스가 있는지 검색한다.
singletonObj = GameObject.FindObjectOfType(typeof(T)) as GameObject;
// 검색 결과가 없다면 빈 오브젝트를 생성하고 목표 컴포넌트를 넣는다.
if (singletonObj == null)
{
singletonObj = new GameObject(typeof(T).Name);
instance = singletonObj.AddComponent<T>();
}
// 검색 결과가 있다면 그 오브젝트에 있는 컴포넌트를 사용한다.
else
{
instance = singletonObj.GetComponent<T>();
if(instance == null)
instance = singletonObj.AddComponent<T>();
}
}
// 상술한 과정으로 얻은 결과물을 반환한다.
return instance;
}
}
}
자, 무엇인가 많이 추가되고 변동되었다.
별 수 없는 것이, 어제의 TIL에서도 말했듯이 AddComponent는 주로 오브젝트를 생성할 때에 쓰이는 함수이기도 하고, '호출하면 그 때 바로 생성이 되게 되는' 구조가 여기저기서 호출되는 싱글톤의 특성 상 가장 간편한 방식이기 때문이다.
그렇다 보니, 전체적으로 C#에서 쓰였던 싱글톤과 방식이 유사해졌다.
여담으로, '호출 시 생성하도록' 구성한다면, 생성된 싱글톤은 모든 필드를 스크립트로 할당해야 하게 된다.
특히 해당 싱글톤이 가져야 하는 컴포넌트가 있다면 이것도 AddComponent로 가져와야 하고, 특정 객체의 정보를 담고 있어야 한다면 Find로 가져와야 한다.
이것을 인스펙터로 할 수 없다는 게 다소 아쉬운 점인데...
사실, 상술한 코드는 씬에 오브젝트를 미리 배치해도 딱히 문제가 없다. FindObjectOfType을 이용해서 목표 컴포넌트를 가진 오브젝트를 검색하는 단계가 있기 때문에 미리 씬에 배치했다면 이 단계에서 존재하는 것으로 간주하여 해당 오브젝트의 목표 컴포넌트를 싱글톤으로 구성하게 되기 때문. 이렇게 미리 배치하면 인스펙터도 활용할 수 있다.
만약에 싱글톤 클래스를 생성할 때 필요한 컴포넌트도 같이 할당하려고 한다면, Instance 호출 자체가 static으로 되어있기 때문에 다소 껄끄럽다는 점에는 주의하도록 하자.
대신 상속받은 클래스의 Awake에서 구현하면 깔끔하게 구성 가능하다.
엄밀히 말하면 생성 직후 할당되는 것은 아니긴 하지만, 인스턴스화 되면서 바로 작동하는 것이기 때문에 비슷한 구성이 되게 된다.
'스파르타 내일배움캠프 > Today I Learned' 카테고리의 다른 글
Today I Learned - Day 29 [ObjectPool에 관하여] (0) | 2024.10.24 |
---|---|
Today I Learned - Day 28 [Raycast] (1) | 2024.10.23 |
Today I Learned - Day 26 [AddComponent] (0) | 2024.10.21 |
Today I Learned - Day 25 [New Input System] (0) | 2024.10.18 |
Today I Learned - Day 24 [객체, 그 개념에 대하여 - 3] (0) | 2024.10.17 |