전체 코드
1. 싱글턴 패턴이란?
✅ 싱글턴(Singleton) 패턴의 개념
- 싱글턴 패턴은 객체를 하나만 생성하고, 이를 전역적으로 접근할 수 있도록 보장하는 디자인 패턴이다.
- 전역적으로 하나의 인스턴스를 공유하며, 여러 곳에서 동일한 인스턴스를 참조할 수 있도록 한다.
✅ 싱글턴 패턴을 사용하는 이유
- 유일성 보장:
- 특정 객체가 프로그램 내에서 단 하나만 존재하도록 한다.
- 예: 게임 매니저, 네트워크 매니저, 설정 관리자 등.
- 일관성 유지:
- 여러 개의 인스턴스가 생성될 경우 데이터가 일관되지 않을 위험이 있음.
- 싱글턴을 사용하면 같은 객체를 공유하므로 데이터의 일관성을 유지할 수 있음.
- 메모리 절약:
- 동일한 인스턴스를 여러 개 생성하지 않기 때문에 불필요한 메모리 사용을 방지할 수 있음.
- 어디서든 접근 가능:
- 전역 접근이 가능하여 편리한 데이터 공유 및 관리가 가능함.
2. 싱글턴을 활용한 게임 매니저 구현
✅ 게임 매니저의 역할
- 게임 전체를 관리하는 중앙 관리 시스템.
Managers 클래스를 싱글턴 패턴으로 만들어 전역적으로 관리할 수 있도록 함.
3. 게임 매니저 오브젝트 가져오기
GameObject obj = GameObject.Find("@Managers");
Managers mag = obj.GetComponent<Managers>();
- 코드 설명:
GameObject.Find("@Managers")
- 현재 씬(Scene) 에 존재하는 오브젝트 중에서 이름이
"@Managers"인 오브젝트를 찾는다.
- 단, 활성화(Active)된 오브젝트만 찾을 수 있다.
obj.GetComponent<Managers>()
"@Managers" 오브젝트에 붙어 있는 Managers 스크립트를 가져와 mag 변수에 저장한다.
✅ 문제점
"@Managers" 오브젝트가 없는 경우 → null 반환
"@Managers" 오브젝트는 있지만 Managers 컴포넌트가 없는 경우 → null 반환
4. 싱글턴 구현 방법
첫 번째 방법: 기본적인 싱글턴 구현
public class Managers : MonoBehaviour
{
static Managers Instance;
public static Managers GetInstance()
{
return Instance;
}
void Start()
{
GameObject obj = GameObject.Find("@Managers");
Instance = obj.GetComponent<Managers>();
}
}
✅ 설명
static Managers Instance
- 정적(static) 변수로 선언하여 단 하나의 인스턴스만 유지하도록 함.
GetInstance()
- 현재 Instance를 반환하는 정적 메서드로 다른 곳에서
Managers.GetInstance()로 접근 가능.
Start()
- 현재 씬에서
"@Managers" 오브젝트를 찾아 Managers 컴포넌트를 Instance에 저장.
❌ 문제점
- "@Managers" 오브젝트가 없으면
Find 함수가 null을 반환하여 오류 발생 가능.
"@Managers" 오브젝트에 Managers 스크립트가 없으면 null이 되어 참조 오류 발생.
5. 개선된 싱글턴 구현
✅ 두 번째 방법: 오브젝트가 없을 경우 자동 생성
public class Managers : MonoBehaviour
{
static Managers Instance;
public static Managers GetInstance()
{
Init();
return Instance;
}
void Start()
{
Init();
}
static void Init()
{
if (Instance == null)
{
GameObject obj = GameObject.Find("@Managers");
if (obj == null)
{
obj = new GameObject { name = "@Managers" };
obj.AddComponent<Managers>();
}
DontDestroyOnLoad(obj);
Instance = obj.GetComponent<Managers>();
}
}
}
✅ 개선 사항
Init() 메서드를 추가하여 초기화 과정을 한 곳에서 관리하도록 함.
Instance == null 인 경우에만 오브젝트를 찾거나 생성하여 불필요한 Find() 호출을 줄임.
"@Managers" 오브젝트가 없으면 자동으로 생성하여 안정성을 높임.
DontDestroyOnLoad(obj) 를 사용하여 씬이 변경되어도 유지되도록 설정.
6. 프로퍼티를 활용한 싱글턴 구현
✅ 세 번째 방법: GetInstance() 대신 프로퍼티 사용
public class Managers : MonoBehaviour
{
static Managers s_instance;
public static Managers Instance
{
get
{
Init();
return s_instance;
}
}
static void Init()
{
if (s_instance == null)
{
GameObject obj = GameObject.Find("@Managers");
if (obj == null)
{
obj = new GameObject { name = "@Managers" };
obj.AddComponent<Managers>();
}
DontDestroyOnLoad(obj);
s_instance = obj.GetComponent<Managers>();
}
}
}
✅ 설명
GetInstance() 메서드를 사용하지 않고 프로퍼티(Instance)로 대체.
Instance 프로퍼티를 호출하면 자동으로 Init()을 실행하여 초기화 진행.
Managers.Instance 로 간단하게 접근 가능.
장점
- 코드가 더 직관적이고 가독성이 좋아짐.
Instance 프로퍼티를 호출할 때만 초기화가 실행됨.
7. 싱글턴 패턴의 장점과 단점
✅ 장점
- 유일성 보장
- 객체가 한 개만 생성되므로 데이터의 일관성이 유지됨.
- 전역 접근 가능
Managers.Instance 로 어디서든 간편하게 접근할 수 있음.
- 메모리 절약
- 동일한 객체를 여러 개 생성하는 것이 아니라 하나의 인스턴스를 재사용함.
❌ 단점
- 전역 접근의 위험
- 프로그램 전체에서 접근 가능하므로 잘못된 사용으로 인해 버그가 발생할 위험이 있음.
- 결합도 증가
- 다른 클래스에서
Managers.Instance를 직접 참조하면 의존성이 증가하여 유지보수가 어려워질 수 있음.
- 멀티스레드 환경에서 문제 발생 가능
- 멀티스레드 환경에서
Instance가 동시에 초기화되면 Race Condition(경쟁 상태) 문제 발생 가능.
- 이를 방지하려면 스레드 동기화 (lock 사용) 을 추가해야 함.