본문 바로가기

PROGRAMMING/Design Pattern

[GoF] 싱글턴 (Singleton) 패턴

싱글턴 (Singleton) 패턴 생성 패턴

클래스에 대응하는 단일의 객체에 대한 전역적인 접근을 허용합니다.


 

어떤 객체는 어떤 코드 영역에서든지 접근할 수 있어야 할 경우가 있다. 환경 설정을 불러오거나, 진행중인 게임의 상태를 가져오거나, 쓰레드 풀을 사용할 경우에 관련 객체에 접근해야 할 것이다. 그럴 때마다 객체를 가져오기엔 실제로 객체가 있는 구조와는 거리가 멀 수도 있고, 객체를 일시적으로 사용하기 위해 생성자 등을 통해 객체를 가져와야 하는 것도 번거로울 것이다. 싱글턴 패턴은 객체가 곧 클래스(객체를 하나만 생성할 수 있음)인 경우에 한해 객체에 대한 전역적인 접근을 허용할 수 있게 한다.

전역 멤버 변수는 클래스 네임스페이스를 통해 프로그램 내 어디에서든지 접근 가능하다는 특징이 있다. 그래서 싱글턴 패턴은 클래스 자신을 가질 수 있는 전역 멤버 변수를 클래스 내에 마련하여 객체를 할당했을 경우에 프로그램 내에서 어디에서든지 동일한 객체를 가져올 수 있게 한다.

이 전역 멤버 변수에 객체를 언제 할당할지에 따라 두 분류로 나눌수 있는데, 외부에서로부터 직접 객체를 생성하여 멤버 변수에 할당하는 방법이 있고, 전역 멤버 변수에 처음 접근하려 할 때(객체가 할당되지 않았을 때) 객체를 내부적으로 생성하여 멤버 변수에 할당하는 방법이 있다. 이 경우엔 프로그램 내에서 싱글턴 객체를 사용하지 않을 때 객체를 할당하지 않아 메모리를 절약할 수 있으나, 외부에서 객체를 직접 생성하는 방법과는 달리 객체의 생성 시점을 파악하기 어려운 점이 있다.

싱글턴 패턴을 이용하여 객체에 접근할 경우 자잘한 코드의 추가 없이 바로 객체를 사용할 수 있어 코드가 간략해지고, 객체의 생성을 제한하였기에 객체의 중복적인 생성을 피할 수 있다. 그러나, 싱글턴 객체를 이용하는 객체는 싱글턴 객체와의 의존성이 필수적으로 발생하게 되고, 객체 지향 프로그래밍에서의 전역 변수 사용은 객체에 대한 생산성의 한계를 강제한다. 그리고 멀티스레딩를 통해 싱글턴 객체에 접근할 경우 객체가 두개 이상 생성되거나 객체의 상태 변화가 적용되지 않는 등 객체의 점유에 대한 다양한 이슈가 발생할 수 있다. (이 경우엔 여러 프로그래밍 언어에서 지원하는 스레드 동기화를 이용해 싱글턴 객체의 사용을 멀티스레딩으로부터 안정화할 수 있다)

그래서 싱글턴 패턴은, 여러 디자인 패턴 중 유독 사용에 주의를 가해야 한다. 객체가 프로그램 내에 단 하나만 존재한다고 규정할 수 있을 경우에만 사용하는 것을 권장한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class PatternSingleton
{
    public class SingletonManual
    {
        private static SingletonManual _instance;
 
        public static SingletonManual GetInstance()
        {
            return _instance;
        }
        
        public static void CreateInstance()
        {
            _instance = new SingletonManual();
        }
 
        public void Operation()
        {
            Console.WriteLine("Operating Singleton (Manual)");
        }
    }
 
    public class SingletonAutomatic
    {
        private static SingletonAutomatic _instance;
 
        public static SingletonAutomatic GetInstance()
        {
            if (_instance == null)
            {
                _instance = new SingletonAutomatic();
            }
 
            return _instance;
        }
 
        public void Operation()
        {
            Console.WriteLine("Operating Singleton (Automatic)");
        }
    }
 
    public static void Main(string[] args)
    {
        SingletonManual.CreateInstance();
 
        SingletonManual.GetInstance().Operation();
 
        SingletonAutomatic.GetInstance().Operation();
    }
}
cs

1
2
3
Operating Singleton (Manual)
Operating Singleton (Automatic)
Press any key to continue . . .
cs

위의 패턴에서는 두개의 싱글턴 클래스를 정의하였다. SingletonManual 클래스는 외부적인 객체의 생성, SingletonAutomatic 클래스는 내부적인 객체의 생성을 지원한다. 두 클래스 다 GetInstance() 함수를 통해 싱글턴 객체를 반환받을 수 있다는 것은 동일하다.