"깊이"가 다른 게임개발자 허민영

유저에서 게임까지, 철학에서 코딩까지, 본질을 보는 게임개발

내일배움캠프

TIL 240212 매니저 클래스의 싱글톤 패턴 개선

허민영 2025. 2. 12. 23:52

오늘은 싱글톤 패턴을 적용한 매니저 클래스를 더 효율적으로 작성하는 방법을 배웠다. 기존에는 일반적인 정적 프로퍼티 방식으로 싱글톤 패턴을 구현했지만, 이를 Lazy<T>를 활용하여 보다 성능적으로 개선할 수 있음을 알게 되었다.

기존 코드 (일반적인 싱글톤 패턴)

기존에는 다음과 같은 방식으로 싱글톤 패턴을 적용한 매니저 클래스를 작성하였다.

class GameManager
{
    public static GameManager Instance { get; } = new GameManager();
}

이 방식은 객체를 정적으로 생성하여 Instance 프로퍼티를 통해 접근할 수 있도록 한다.
하지만 이 방식에는 몇 가지 문제점이 존재한다.

  1. 즉시 초기화(Eager Initialization)
    • GameManager 클래스가 참조되면 즉시 인스턴스가 생성된다.
    • 인스턴스가 실제로 필요할 때까지 생성이 지연되지 않는다.
  2. 쓰레드 안전성 보장 부족
    • 멀티쓰레드 환경에서 객체 생성 시 동기화가 자동으로 이루어지지 않아, 별도의 조치가 필요할 수 있다.

 

개선된 코드 (Lazy<T>를 활용한 싱글톤 패턴)

이번에 배운 방법을 적용하여, 보다 효율적인 싱글톤 매니저 클래스를 작성할 수 있다.
이를 위해 제네릭과 Lazy<T>를 활용한 싱글톤 매니저 클래스를 만들었다.

public abstract class Manager<T> where T : Manager<T>, new()
{
    private static readonly Lazy<T> _instance = new Lazy<T>(() => new T());

    public static T Instance => _instance.Value;

    protected Manager() 
    {
        Console.WriteLine($"{typeof(T).Name} 생성됨!");
    }
}

 

이 방식은 기존 방식과 비교했을 때 다음과 같은 장점이 있다.

  1. 지연 초기화(Lazy Initialization) 적용
    • Lazy<T>를 사용하여 인스턴스가 실제로 필요할 때까지 생성이 지연된다.
    • 불필요한 객체 생성을 방지할 수 있다.
  2. 쓰레드 안전성(Thread Safety) 보장
    • Lazy<T>는 기본적으로 쓰레드 안전성을 제공하므로, 멀티쓰레드 환경에서도 안전하게 사용할 수 있다.
  3. 제네릭을 활용한 확장성 제공
    • Manager<T>를 상속받아 여러 매니저 클래스를 쉽게 생성할 수 있다.

예를 들어, GameManager를 Manager<T> 기반으로 정의하면 다음과 같이 작성할 수 있다.

public class GameManager : Manager<GameManager>
{
}

 

이제 GameManager.Instance를 호출하면, Lazy<T>를 활용하여 객체가 안전하게 생성된다.

 

배운 점

  • Lazy<T>를 활용하면 싱글톤 객체의 생성을 필요할 때까지 지연할 수 있다.
  • 멀티쓰레드 환경에서도 안전한 싱글톤 패턴을 구현할 수 있다.
  • 제네릭을 활용하면 싱글톤 매니저 클래스를 더 확장성 있게 설계할 수 있다.
  • 기존의 static 방식과 비교하여 성능적으로 더 효율적인 방법이라는 점을 이해하였다.

이번 학습을 통해 보다 유지보수성이 높고 안전한 싱글톤 패턴을 적용할 수 있는 방법을 익힐 수 있었다.