ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Singleton 패턴
    CS 2025. 8. 7. 11:55

    Singleton 패턴이란?

    "하나의 클래스에 대해 오직 하나의 인스턴스만 존재하도록 보장하고, 그 인스턴스에 접근할 수 있는 전역적인 접근점을 제공하는 패턴"

    Singleton 패턴 구현 방법

     C# 구현 예시 - Lazy Initialization

    public class Singleton {
        private static Singleton instance;
    
        private Singleton() {
            // private 생성자
        }
    
        public static Singleton Instance {
            get {
                if (instance == null) {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }

     

    위 코드의 문제점은 단일 스레드에선 잘 동작하지만 멀티 스레드 환경에서는 잘 동작하지 않을 수 있음. 

     

     

    개선 코드 

    public class Singleton
    {
        private static readonly Lazy<Singleton> lazyInstance =
            new Lazy<Singleton>(() => new Singleton());
    
        private Singleton() {}
    
        public static Singleton Instance => lazyInstance.Value;
    }

     

    Lazy를 사용하면 해결할 수 있다. 내부적으로 lock을 구현해주기 때문에 멀티스레드 환경에서 안전함.

     

     

    Singleton 패턴의 장점

    1. 인스턴스가 하나만 존재하므로 메모리 낭비를 방지
    2. 전역 접근이 가능하여 상태 공유가 쉬움
    3. 객체 생성을 제어할 수 있어 리소스 사용을 관리하기 용이

    DB 생성과 같은 부분에 많이 쓰이게 됨

    Singleton 패턴의 단점과 극복 방법

    TDD(Test Driven Development)를 할 때 걸림돌이 된다. 단위 테스트를 할 때 각 테스트마다 독립적인 객체를 만들기 어렵기 때문이다. 이는 의존성 주입(DI)를 통해 어느정도 해결할 수 있다. 

     

    예시 코드와 함께 살펴보자. 

    public class Service
    {
        public void DoWork()
        {
            var logger = Logger.Instance; // 직접 Singleton에 의존
            logger.Log("작업 시작");
        }
    }

     

    이 코드의 문제점은 Logger가 Singleton에 직접 접근하기 때문에 가짜 객체(mock)를 사용할 수 없다는 것이다. 

     

    다음과 같이 인터페이스로 구현해보자. 

    public interface ILogger
    {
        void Log(string message);
    }
    
    public class Logger : ILogger
    {
        private static readonly Logger instance = new Logger();
    
        private Logger() {}
    
        public static Logger Instance => instance;
    
        public void Log(string message)
        {
            Console.WriteLine($"[Log] {message}");
        }
    }

     

    이렇게 되면 실제로 로그를 찍는 클래스는 다음과 같이 구현돤다. 

    public class Service
    {
        private readonly ILogger _logger;
    
        public Service(ILogger logger) // 생성자 주입
        {
            _logger = logger;
        }
    
        public void DoWork()
        {
            _logger.Log("작업 시작");
        }
    }

     

    단위 테스트는 다음과 같이 할 수 있다. 

    public class FakeLogger : ILogger
    {
        public List<string> Logs = new List<string>();
    
        public void Log(string message)
        {
            Logs.Add(message); // 실제 로그 대신 저장
        }
    }
    
    // 테스트 코드
    public void Test_Service_LogsWorkStart()
    {
        var fakeLogger = new FakeLogger();
        var service = new Service(fakeLogger);
    
        service.DoWork();
    
        Debug.Assert(fakeLogger.Logs.Contains("작업 시작"));
    }

     

    'CS' 카테고리의 다른 글

    Apache Spark  (0) 2025.11.26
    Apache Kafka  (0) 2025.11.26
    면접을 위한 JAVA 정리  (0) 2025.11.17
    면접을 위한 C 정리  (0) 2025.11.17
    면접을 위한 DB 정리  (0) 2025.11.14
Designed by Tistory.