싱글톤이 뭐에요?
간단히 말해, “하나의 클래스 인스턴스만 존재하도록 보장하고, 그 인스턴스를 전역적으로 공유하자!” 라는 철학이 담긴 디자인 패턴이에요.
우리 게임에서 사운드 매니저, 게임 매니저 같은 애들은 굳이 여러 개가 있을 필요가 없잖아요. 여기저기서 귀찮게 FindObjectOfType
같은 거 돌리지 말고, 하나만 확실하게 잡아놓고 전역으로 꺼내 쓰자… 그게 싱글톤입니다.
왜 싱글톤을 써야할까?
- 전역 접근
- "어디서든"
Manager.Instance
이런식으로 호출할 수 있어서 편해요. - 특히 공통 데이터나 시스템은 여기저기서 참조가 많이 필요한데, 그럴 때 아주 간단하게 불러올 수 있어요.
- "어디서든"
- 중복 방지
- 사운드 매니저나 게임 매니저가 두 개, 세 개씩 생겨서 꼬이는 일을 없게 만들어줘요.
- "이미 만들어진 싱글톤이 있다면 난 죽겠다!"라는 느낌으로 새로 생긴 객체를 파괴하니까 인스턴스가 하나만 유지된다는 것을 보장할 수 있어요.
- 코드의 간결함
- 여차하면
SoundManager.Instance.PlayBGM()
같은 형태로 쉽게 코드를 짤 수 있어서 로직이 깔끔해지죠. - 소규모 프로토타입을 만들 때도 빠르게 "딸깍!" 하고 만들기 좋아요.
- 여차하면
어떻게 써요?
유니티에서는 MonoBehaviour
기반 싱글톤을 주로 써요.
MonoBehaviour
상속 싱글톤
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : Component
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<T>();
if (_instance == null)
{
GameObject obj = new GameObject();
obj.name = typeof(T).Name;
_instance = obj.AddComponent<T>();
}
}
return _instance;
}
}
// 외부에서 new로 생성 막기
protected Singleton() { }
private void Awake()
{
if (_instance == null)
{
_instance = this as T;
DontDestroyOnLoad(this);
}
else
{
Destroy(this);
}
}
}
주요 포인트
Instance
프로퍼티: 인스턴스가 없으면 찾고, 그래도 없으면 만들고. 이미 있으면 그거 재활용!Awake()
에서DontDestroyOnLoad
로 씬 이동에도 죽지 않게 해주고, 중복 생기면Destroy
로 없애버려요.
MonoBehaviour
가 아닌 일반 C# 클래스 싱글톤
public class MySingletonClass
{
private static MySingletonClass instance;
public static MySingletonClass Instance
{
get
{
if (instance == null)
instance = new MySingletonClass();
return instance;
}
}
private MySingletonClass() { }
// ...
}
- 이 경우 유니티 라이프사이클 메서드(
Awake
,Update
등)를 못 써요. - 씬 전환과 상관없이 데이터를 관리하거나, 게임 로직만 처리하는 데는 이런 방법이 깔끔할 때가 많죠.
문제점 & 주의사항
- 남용 주의
- 편리함 때문에 너무 많은 싱글톤 매니저가 생겨나면, 프로젝트 전체가 전역 인스턴스에 의존하게 되어 디버깅이나 유지보수가 복잡해질 수 있어요.
- “정말 전역으로 1개만 있어야 하나?”를 항상 고민해보고, 필요한 경우에만 쓰는 게 좋아요.
- 테스트 & 확장성 저해
- 하나뿐인 인스턴스를 여기저기서 끌어다 쓰면, 단위 테스트가 난감해져요.
- 나중에 구조 바꾸거나 모듈화하려 할 때, 싱글톤 인스턴스가 걸리적거릴 수 있습니다(결합도가 높아서).
- 씬 전환 주의
DontDestroyOnLoad
로 씬 전환 때도 객체가 유지되는데, 중복되면 서로가 싸우다가 꼬일 수 있어요.- 씬마다 동일한 매니저 객체를 배치해놓거나, 복수 씬을 additive로 불러오는 구조라면, 각별히 신경 쓰세요.
- DI(Dependency Injection) 고려
- Zenject(Extenject) 같은 DI 프레임워크를 쓰면 “전역 접근”보다는 “필요한 곳에 필요한 인스턴스를 주입”하는 식으로 더 유연하게 짤 수도 있어요.
- 프로젝트가 커지고 복잡해질수록 DI가 싱글톤보다 더 깔끔할 수도 있어요.
마무리
정리하자면, 싱글톤은 "딱 하나만 있어야하는 시스템"을 쉽고 빠르게 구현해주는 멋진 수단이에요.
- 전역억으로 접근하기 쉬워서 간단한 소규모 프로젝트나 프로토타입 단계에서는 굉장히 유용하죠.
- 하지만, 무작정 남용하면 "예상치 못한 종속성"이 마구마구 생겨나서 유지보수할때 머리가 아파질 수 있어요.
핵심: “정말 한 개만 필요한지” + “전역으로 접근해야만 하는지”를 늘 고민하고, 필요하다면 과감히 싱글톤을 쓰되,
혹여 의존성이 심해지고 테스트가 어려워진다면 DI나 ScriptableObject, 이벤트 시스템 등 다른 대안도 생각해보세요.
이상으로 유니티 개발에 빼놓기 어려운 싱글톤에 대한 이야기였습니다. 더 좋은 팁이나 잘못된 점 이 있다면 댓글로 알려주세요.
'Develop > Unity' 카테고리의 다른 글
[Unity] 오브젝트 풀링 (Object Pooling) (1) | 2025.01.08 |
---|