티스토리 뷰
유지보수시에 버그 발생을 높이고 디버깅이 힘들어지므로 되도록 멀리하는것이 좋지만 게임과 같은 특정분야에서 성능이나 효율성(소규모개발)을 이유로 Singleton Pattern이 많이 쓰이는것 같아 정리하도록 한다.
## 개요
MonoBehaviour나 ScriptableObject같은 Unity Object를 Singleton으로 만들수도 있지만 객체 설계 취지에서 벗어나고 객체 lifetime에 대한 제어권이 Unity C++ Engine에 있다는게 찝찝하기에 개인적으로는 사용을 지양한다.
참고로 대충 아래와 같은 방식으로 `Awake()`를 통해 초기화하해서 사용하며 안정성을 위해 부가 코드가 추가될 수 있다.
## MonoBehaviour Singleton
보통 싱글톤을 상속과 일반화를 통해 많이 만들겠다는 생각은 좋은 생각이 아니다.
다만, Unity 소규모 프로젝트에서 개발효율을 위해 각종 매니저들을 싱글톤으로 구성하는 경우가 있는듯하다.
이 경우 아래와 같이 사용 가능하다.
internal abstract class SingletonMonoBase<T> : MonoBehaviour
where T : MonoBehaviour
{
private static readonly Lazy<T> _lazy =
new Lazy<T>(CreateInstanceOfT);
public static T Instance => _lazy.Value;
private static T CreateInstanceOfT()
{
T monobehaviourInstance = FindObjectOfType<T>();
if (monobehaviourInstance == null)
{
GameObject gameObj = new GameObject(typeof(T).Name);
monobehaviourInstance = gameObj.AddComponent<T>();
DontDestroyOnLoad(gameObj);
}
return monobehaviourInstance;
}
// 필요시 Unity Message를 통한 부가적인 처리
protected virtual void Awake() { }
protected virtual void OnDestroy() { }
protected virtual void OnApplicationQuit() { }
}
// 사용시
internal sealed class DerivedSingletonMono : SingletonMonoBase<DerivedSingletonMono>
{
//protected override void Awake()
//{
// base.Awake();
// // 필요시 부가적인 처리 ...
//}
//protected override void OnApplicationQuit()
//{
// base.OnApplicationQuit();
// // ...
//}
//protected override void OnDestroy()
//{
// base.OnDestroy();
// // ...
//}
}
Lazy<T>를 통해 `Instance`프로퍼티가 호출될때 static readonly인 _lazy 멤버변수의 초기화가 `CreateInstanceOfT` static method를 통해 발생한다. Scene객체, Prefab, Addressables 및 Script 등을 통해 싱글톤으로 사용 가능하다. 몇가지 허점이 있지만 Awake, OnDestory와 같은 이벤트를 통해 필요시 보완이 가능하다.
## ScriptableObject Singleton (비추천)
- References 링크 참조
- ScriptableObject 개념 자체가 메모리 공유이므로 이걸 다시 싱글톤으로 만들겠다는 발상 자체가 잘못된것일 수 있다.
## Pure C#
보통 앱실행 시점에 모든 인스턴스를 다 로드해버리면 사용자 사용성 및 리소스 효율성 등 문제가 발생하기 때문에 Lazy instantiation(사용하는 시점에 필요하다면 인스턴스화)을 사용하기도 한다.
아래 thread-safe한 방법중 Lazy instantiation 필요성에 따라 적절하게 사용하면 될듯하다.
1. Lazy instantiation이 필요없는 일반적인 경우(App Domain 올라올때 인스턴스화)
internal sealed class Singleton
{
private static readonly Singleton _instance = new Singleton();
public static Singleton Instance { get { return _instance; } }
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton() { }
private Singleton() { }
}
2. Lazy instantiation이 필요한 경우 (C# 4.0 & .NET Framework 4.0 이상)
internal sealed class Singleton
{
private static readonly Lazy<Singleton> _lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return _lazy.Value; } }
private Singleton() { }
}
Lazy<T>의 경우 기본적으로 thread-safety를 지원한다.
2-1. 추상화 버전 (비추천)
internal abstract class SingletonBase<T> where T : class
{
private static readonly Lazy<T> _lazy =
new Lazy<T>(() => Activator.CreateInstance(typeof(T), true) as T);
public static T Instance => _lazy.Value;
protected SingletonBase() { }
}
// 사용시
internal sealed class DerivedSingleton : SingletonBase<DerivedSingleton>
{
DerivedSingleton() : base() { }
}
상속과 일반화까지 사용해 싱글톤을 많이 만들겠다는 소리는 설계를 뭔가 잘못하고 있다는걸 의미할수도 있다.
무차별적인 싱글톤 남용은 프로젝트 확장시 지옥을 만들 수 있으므로 추천하지 않는다.
3. Lazy instantiation이 필요한 경우 (C# 4.0 & .NET Framework 4.0 미만)
internal sealed class Singleton
{
public static Singleton Instance { get { return Nested.Instance; } }
private Singleton() { }
private class Nested
{
internal static readonly Singleton Instance = new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested() { }
}
}
## References
https://csharpindepth.com/articles/singleton
'Game > 개발' 카테고리의 다른 글
[Unity] Addressables (v1.19.19 기준 - Editor 2021.3) (0) | 2023.03.23 |
---|---|
[Unity] Assembly Definition (어셈블리 정의) (0) | 2023.03.16 |
[Unity] Preprocessor directives & Conditional Compilation (전처리기 지시문 및 조건부 컴파일) (0) | 2023.03.15 |
[Unity] 엔진의 주요 event 함수 정리 (Awake(), Start(), etc) (2) | 2023.03.10 |
[RuntimeInitializeOnLoadMethod] Unity 런타임 초기화 method 정의를 위한 attribute (0) | 2022.10.20 |
- Total
- Today
- Yesterday
- framework
- firestore
- github
- 유니티
- vscode
- Debug
- .net
- 비동기
- VS2022
- Visual Studio Code
- git
- Singleton
- 싱글톤
- await
- 닷넷
- logging
- unity
- coroutine
- C#
- Custom Package
- async
- initialize
- 환경설정
- gcp
- Scraping
- RuntimeInitializeOnLoadMethod
- Python
- selenium
- 코루틴
- Addressables
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |