싱글톤 패턴 ( Singleton Pattern )

게임 내에서 파괴되지 않고 지속적으로 존재하며 데이터를 관리해줘야 하는 객체가 필요하다.
그리고 그 객체에 조금 더 편하게 접근할 수 있다면 게임을 제작하기 더 편해질 수 있다.
싱글톤 패턴은 위의 의문들에 대한 해답을 제공한다.
프로그램 내에서 단 하나의 객체만 존재하는 컨트롤 타워로서 프로그램의 시작부터 종료시까지 생존한다.
그렇기 때문에 데이터 관리에 있어 이점을 가진다.
싱글톤 패턴을 쓰지 않을수가 없을 정도로 필수적인 디자인 패턴이다
하지만 유용하고 편리하면서도 단점이 많은 아이러니한 패턴이다.
싱글톤 패턴은 게임 구현에서 가장 많이 사용되는 디자인 패턴중 하나이다.
단일의 인스턴스와 전역적인 접근을 제공하며 이러한 특성은 장점과 동시에 단점으로 작용한다.
- 클래스의 인스턴스가 딱 1개만 존재해야 할 때 사용한다.
- 모든 스크립트에서 그 인스턴스에 쉽게 접근할 수 있다.
- 전역 변수처럼 사용할 수 있지만 , 객체 지향적으로 안전하게 관리할 수 있다.
Unity 에서도 GameManager , AudioManager , DataManager 처럼 전역적으로 관리되는 객체를 만들 때 자주 사용한다.
예시 코드
public class GameManager
{
// 1. 유일한 인스턴스 보관용
private static GameManager instance;
// 2. 외부에서 접근할 수 있는 프로퍼티
public static GameManager Instance
{
get
{
if (instance == null)
instance = new GameManager(); // 없으면 새로 생성
return instance;
}
}
// 3. 외부에서 직접 생성 방지
private GameManager() { }
public void PrintHello()
{
Debug.Log("Hello, Singleton!");
}
}
▼사용
GameManager.Instance.PrintHello();
Unity 싱글톤 예시 ( MonoBehaviour 상속 )
Unity 의 경우 new 로 생성할 수 없기 때문에 Awake( ) 에서 관리한다.
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject); // 이미 있으면 중복 제거
return;
}
Instance = this;
DontDestroyOnLoad(gameObject); // 씬 전환 시 유지
}
}
- 싱글톤 남용은 의존성 증가나 유닛 테스트 어려움을 초래할 수 있다
- 게임 전체 상태 관리용이나 공유 리소스 관리용에만 사용하는 것이 좋다
- Awake( ) 보다 먼저 접근하지 않도록 주의 ( 아직 Instatcs 가 null 일 수 있다 )
싱글톤에서 Awake( ) 가 사용되는 이유
Awake( ) 는 씬에 오브젝트가 생성되자마자 가장 먼저 호출되기 때문에 전역 인스턴스를 등록하기에 가장 안전한 시점이다
void Awake()
{
if (Instance == null)
Instance = this;
else
Destroy(gameObject);
}
이렇게 하면 게임이 시작되자마자 Instance 가 설정된다.
다른 스크립트들이 안심하고 GameManager.Instance 를 사용할 수 있다.
싱글톤이 필요한 이유
Unity 게임에는 이런 종류의 오브젝트가 많이 있다.
| 예시 | 설명 |
| SoundManager | 배경음악 , 효과음 등을 전역에서 제어해야 한다 |
| GameManager | 스테이지 , 점수 , 생명 , 설정 등 게임 전체 상태 관리 |
| UIManager | 여러 씬에서 공통 UI ( 체력바 , 미니맵 등 ) 관리 |
| DataManager | 플레이어 정보 , 세이브 파일 , 설정 데이터 유지 |
이런 것들은 씬을 바꿔도 사라지면 안되고 프로그램 전체에서 하나만 존재해야 한다.
그런데 일반 오브젝트들은 씬이 바뀌면 Destroy 되어 사라진다.
그래서 하나만 존재하고 계속 유지되도록 만드는 게 바로 싱글톤이다.
▼예시 코드
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
// 이미 인스턴스가 있으면 자기 자신 삭제
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
// 처음 생성된 자신을 Instance로 등록
Instance = this;
DontDestroyOnLoad(gameObject); // 씬 이동해도 유지
}
}
이제 다른 스크립트에서 GameManager.Instance 로 바로 접근이 가능하다
GameManager.Instance.AddScore(10);
싱글톤 없음 : 각 씬마다 GameManager 가 새로 생성되어 점수 , 설정이 초기화된다
싱글톤 있음 : 첫 씬에더 만든 GameManager 가 계속 유지되며 모든 씬에서 같은 데이터 공유
주의할 점
- 인스턴스 중복 생성 방지
Awake( ) 에서 if (instatnce != null ) 검사 없이 new 나 Instantiate 로 여러 개가 생기면 오류 유발
씬 전환 시 DontDestroyOnLoad 를 사용하면 중복 생성되기 쉽다. - 쓰레드 안전성 ( Thread Safety )
멀티쓰레드 환경 ( 특히 서버 , 툴 코드 등 ) 에서는 동시 접근 시 인스턴스가 중복 생성될 수 있다. ( lock 문 필요 ) - 의존성 증가 ( 결합도 문제 )
전역 접근 ( Global Access )은 편리하지만 , 테스트와 유지보수성 저하
객체 간 의존성이 강해져 구조가 복잡해질 수 있다. - 파괴 타이밍 문제
게임 종료 직전에 인스턴스 접근 시 null 오류 발생 가능
OnDestroy 이후 접근 주의 - 제네릭 기반 싱글톤 사용 시 주의
MonoBehaviour 상속과 제네릭 혼용은 Unity의 컴포넌트 생성 구조와 충돌 가능성이 있다.
따라서 MonoBeHaviour 전용 싱글톤 클래스와 순수 C# 싱글톤 클래스를 구분해 설계하는 것이 좋다.
정리
전역에서 하나만 존재하도록 보장되는 인스턴스
편리하지만 남용 시 의존성과 유지보수 문제가 생긴다
참고 자료
https://gameprogrammingpatterns.com/singleton.html
'🧊Unity Basic > 디자인패턴' 카테고리의 다른 글
| Adapter Pattern 핵심 코드 (0) | 2025.10.24 |
|---|---|
| Observer Pattern (0) | 2025.10.21 |
| Singleton 과 Generic (0) | 2025.10.21 |
| Adapter Pattern (0) | 2025.10.19 |
| Design Pattern (0) | 2025.10.18 |