공부/Unity & C#

[Unity] 디자인패턴 : Singleton 싱글톤 패턴

knhoo 2025. 1. 10. 14:17
728x90

싱글톤

 

싱글톤 패턴은 특정 클래스의 인스턴스를 하나만 생성하고, 어디에서든 그 인스턴스에 접근할 수 있도록 

보장하는 디자인 패턴이다.

 

  • 클래스가 자신의 인스턴스 하나만 인스턴스화할 수 있도록 보장
    • 여러개를 만들어도 하나만 남음
  • 해당 단일 인스턴스에 대한 손쉬운 전역 엑세스를 제공
  • 하나의 객체만 존재할 필요가 있을 때
    • 상태창
    • 게임 매니저
    • 오디오 매니저
    • 파일 관리자
    • UI Settings
    • 등등
  • 안티 패턴으로 취급되기도 함
    • 양날의 검
  • 커플링 발생하기 쉬운 구조
  • 멀티스레드 환경에서는 동기화 처리가 필요
  • 테스트 및 디버깅이 불편
    • 생성 시점이 명확하지 않음

=> 필요한 경우에만 주의해서 사용해야 한다.

 

싱글톤 코드

using UnityEngine;

public class SimpleSingleton:MonoBehaviour{
	public static SimpleSingleton instance;
   
    private void Awake(){
    	if(instance == null){
        	instance = this;
        }
        else{
        	Destroy(gameObject);
            }
        }
   }
   //새 Scene을 부르면 GameObject가 지워짐
   //사용되기 전에 하이어라키에서 셋업 되어야함

자기 자신의 인스턴스를 static으로 가지고 있다.

클래스에서 static으로 선언되면 여러 인스턴스가 있더라도 메모리 공간을 하나만 차지하게된다.

 

MonoBehaviour을 사용하지 않는 경우(씬에 올리지 않는 경우)

using UnityEngine;

public class SimpleSingleton{//MonoBehaviour을 안쓰는 경우
	public static SimpleSingleton Instance;
   
    public static SimpleSingleton Instance{
    	get{
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
            }
        }
   }

멀티 쓰레드 환경에서는 문제가 될 수 있다.

쓰레드 세이프 X

 

⬇️ 개선 코드 ⬇️

public class SimpleSingleton{
	private static bolatile SipleSingleton instance = null;
    private static readonly object padlock = new object();
    ...
    public static SimpleSingleton Instance{
    	get{
        	if(instance ==null){
            	lock(padlock){
                	if(instance == null){
                    	instance = new SimpleSingleton();
                    }
                }
           }
           return instance;
       }
   }
}

//또는

public sealed class SinpleSingleton{
	private static readonly SimpleSingleton instance = new SimpleSingleton();
    //Private constructor ensures that an object is not instantiated from outside the class
    private SinpleSingleton(){
    }
    
    //Public static property to get the single instance of the class
    public static SimpleSingleton Instance{
    	get{
        	return instance;
        }
    }
}

다른 씬을 불러와도 삭제되지 않도록 개선된 코드

using UnityEngine;

public class Singleton:MonoBehaviour{
	public static Singleton instance;
    public static Singleton Instance{
    	get{
        	if(instance==null){
            	SetupInstance();
            }
            return instacne;
        }
    }
   
    private void Awake(){
    	if(instance == null){
        	instance = this;
            DontDestroyOnLoad(this.gameObject);
            //씬을 내려도 파괴되지 않도록 설정
        }
        else{
        	Destroy(gameObject);
            }
        }
   }

	private static void SetupInstance(){
    	instance = FindObjectOfType<Singleton>();
        
        if(instance == null){
        	GameObject gameObj = new GameObject();
            gameObj.name = "Singleton";
            instance = gameObj.AddComponent<Singleton>();
            DontDestroyOnLoad(gameObj);
        }
    }

싱글톤이 여러개 있는 경우

public calss Singleton<T>:MonoBehaviour where T : Component
{
	private static T instance;
    public static T Instance{
    	get{
        	if(instance == null){
            	instance = (T)FindObjectOfType(typeof(T));
                if(instance == null){
                	SetupInstance();
                }
            }
            return instance;
        }
    }
    
    
    public virtual void Awake(){
    	RemoveDuplicates();
    }
    
    private static void SetupInstance(){
    	instance = (T)FindObjectOfType(typeof(T));
        if(instance == null){
        	GameObject gameObj  new GameObj();
            gameObj.name = typeof(T).Name;
            instance = gameObj.AddComponent<T>();
            DontDestroyOnLoad(gameObj);
        }
    }
    
    private void RemoveDuplicates(){
    	if(instance == null){
        	instance = this as T;
            DontDestroyOnLoad(gameObject);
		} else{
        	Destroy(gameObject);
        }
    }
    
    
    ////////////////////////////////////////
    public class GameManager:
    	Singleton<GameManager>{
        //...
        }

 

 

출처 : https://youtu.be/Tf_VZEgnag0?si=Wmr3LBmxagc6Uo0i

728x90