본문 바로가기
- Unity/let us all UNITE !

[Unity, C#] Singleton 싱글톤

by david_동근 2025. 9. 7.

혼자야?

어 아직 싱글톤이야

 


 

Singleton

프로그램(게임) 전체에서 객체가 하나만 생성되는 것을 보장하고,

그 프로그램의 어디에서든지 접근할 수 있도록 만드는 디자인 패턴 중 하나입니다.

가장 간단한 예시로, GameManager, SoundManager, RenderingManager 등... 이 있습니다.

 

(Design-Pattern 관련해서는 아래에 정리해 두었어용)

https://bulletprooves.tistory.com/46

 

[OOP] Design Patterns ( GoF )

Object Oriented 프로그래밍에서 협업을 위해 설계를 할때,내가 작성한 코드, 다른 분께서 작성한 코드를 전달해줄 때 생기는 어려움을 극복하기 위해디자인 패턴이라는 일종의 의사소통 방법을 사

bulletprooves.tistory.com

 

언제 사용?

전역(static)상태가 필요할 때, (설정 값이나 리소스 캐시 등등)

동일한 리소스를 여러 곳에서 공유할 때(사운드 재생, 네트워크 세션 등등) 사용할 수 있겠습니다.

 

그렇기 때문에, 간편하게 접근할 수 있고, 하나만 존재 해야하는 일관성(SOLID 원칙 중 하나인 SRP), 등의 장점이 있습니다.

(아래는 SOLID 설계 원칙 정리한 포스트에용)

https://bulletprooves.tistory.com/67

 

[OOP] SOLID 설계 원칙

solid한 사람이 되어야겠습니다. SOLID 설계 원칙SOLID는 Object-Oriented(객체 지향) 설계의 5가지 핵심 원칙을 말합니다.각각 SRP, OCP, LSP, ISP, DIP 이 5개의 원칙을 의미하며, 유지보수와 확장성을 높입니

bulletprooves.tistory.com

 

하지만, 전역상태에서는 숨은 Dependency(의존성) 이 높을 수 있고, 초기화 순서나 생명 주기(관리하지 않을 경우),

등에서 문제가 일어날 수도 있습니다.

 

간단 예시

C# 의 퓨어 클래스 예시로 Lazy<T> 를 사용해 쓰레드에서 안전한 지연 초기화 예시를 보겠습니다.

public sealed class GameConfig
{
    private static readonly Lazy<GameConfig> _instance =
        new Lazy<GameConfig>(() => new GameConfig());
    public static GameConfig Instance => _instance.Value;

    private GameConfig() {} // 외부에서 new 금지
    public float MasterVolume { get; set; } = 0.8f;
}

 

Unity 예시

유니티의 MonoBehavior 싱글톤 예시 코드를 보겠습니다.

유니티의 경우는 public static 클래스이름 Instance 이렇게 전역 프로퍼티로 구현할 수 있습니다.

using UnityEngine;

public class SoundManager : MonoBehaviour
{
    public static SoundManager Instance { get; private set; } // 얘로 가져오게 되죵,
    // get 은 누구나 가능하지만, set 은 클래스 내부에서만 하도록,

    void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject); // 중복 생성 방지를 위해 추가한 것일 뿐, 
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject); // 씬 전환에도 유지되는 메서드에용
    }

    public void PlaySfx(AudioClip clip) { /* 어쩌구 저쩌구 */ }
}

 

static 정적 타입으로 만들었으니, new 로 만들 객체 없이 그냥

SoundManager.Instance 로 바로 접근할 수 있습니다.

 

클래스 외부에서는 아래처럼 사용합니다.

SoundManager.Instance.PlaySfx(clip);

// null 체크는 해주면 좋지용
if (SoundManager.Instance != null)
{
    SoundManager.Instance.PlayTheme("TitleTheme");
}

 

추가) 왜 필드 대신 프로퍼티냐? 필드는 누구나 자유롭게 바꿀 수 있기 때문에, 보통 프로퍼티로 합니다.

(그래야 싱글톤 보장의 통제 용이성(?)이었나가 된다고 했던 거 같네용)

public static SoundManager Instance; // 필드라면 누구나 자유롭게 바꿀 수 있어서 노노

public static SoundManager Instance { get; private set; } // 외부에서 값 할당 불가 굿굿

 

노트 메모)

- DI(의존성 주입)으로, VContainer나 Zenject 처럼 인터페이스 기반 주입 -> 숨은 의존성을 낮추고 테스트에 좋음

- 정적 클래스같은 경우는 순수 유틸 메서드만 있을 때

- ScriptableObject 싱글톤은 데이터 중심 전역 설정할 때 사용

 


 

싱글톤은 딱 하나만 필요한 객체일 때, 하지만 책임은 항상 너무 과하지 않게!

유니티 같은 경우, 씬, 생명주기, 중복생성 등 대비를 (위한 코드도) 고려해야 해용.

그럼 좋은 하루 되셔요~ ⌯ᵔ⤙ᵔ⌯ಣ

'- Unity > let us all UNITE !' 카테고리의 다른 글

[Unity] LoadAssetAsync Release InstantiateAsync ReleaseInstance  (0) 2025.12.02
[Unity] UniTask 의 토큰 Token (= CancellationToken)  (1) 2025.10.07
[Unity] UniTask  (3) 2025.07.10
[Unity] UniTask  (0) 2025.07.03
[Unity] NGUI  (0) 2025.07.02