티스토리 뷰

오늘은 싱글톤 패턴에 대해 소개해보려고 합니다.

제가 제일 처음 접한 디자인패턴이라, 여러모로 특별한 의미를 가지는 디자인 패턴이고, 제가 생각하기엔, 가장 많이 활용되는 디자인패턴이 아닌가 싶습니다.



1. 싱글톤 패턴이란?

 Single, 즉, 단 하나밖에 없는 인스턴스입니다.

특징은 생성자가 여러번 호출 되도 결국 이 인스턴스는 전체를 통틀어 단 하나밖에 없는 것이 특징입니다. 

예를 들자면, 한 프로그램 통틀어서 필요한 기본설정 정보는 굳이 여러 개일 필요가 없습니다. 설정정보는 하나만 가지고 있고, 설정이 필요한 곳에서 설정 정보를 이 싱글톤으로 받아 쓰게 구현 하면, 중복을 줄일 수 있습니다.

이 디자인의 특징적인 면은, 처음부터 전체 코드에 통틀어 한 객체 밖에 못 만들게 설계 되어 있다는 점에 있습니다.


주저리주저리 하는 설명 보단, 코드를 직접 보며 이해하는 것이 좀 더 빠르다고 생각합니다. 


2. 구현

HeadFirst의 초콜릿공장 예제를 사용하고, C++을 이용하여 구현했습니다. 코드와 함께 설명해보겠습니다.

초콜릿을 끓이는 장치가 있습니다. 이 장치를 초콜릿 보일러로 지칭하겠습니다. 이 초콜릿보일러는 초콜릿 재료를 받아와서, 끓여 녹이고 다음 공정으로 넘기는 역할을 수행하는 장치입니다. 그래서 재료를 채우고(Fill()), 재료를 끓이고 (Boil()), 완성된 내용물을 다음 단계로 넘기는(Drain()) 기능이 구현되어 있습니다.


<CChocolateBoiler.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cstdio>
 
class CChocolateBoiler {
 
public:
    static CChocolateBoiler * GetInstance();
    bool IsBoiled();
    bool IsEmpty();
    void Fill();
    void Drain();
    void Boil();
 
private:
    CChocolateBoiler() :
            bEmpty(true),
            bBoiled (false) {};
    bool bEmpty;
    bool bBoiled;
    static CChocolateBoiler *mChocolateInstance;
};
 
cs


제가 구현한 헤더입니다. 이 헤더에 특징적인 면이 있다면 생성자가 private로 선언되어 있다는 점입니다.


그리고 인스턴스도 정적 인스턴스로 클래스 내에 선언되어 있습니다. static 함수인  GetInstance()가 불려졌을 때, 해당 싱글톤 인스턴스가 만들어져 있지 않으면, GetInstance()가 불려졌을 때 해당 싱글톤 인스턴스가 만들어져 있지 않다면, GetInstance()  함수 내에서 새로운 객체를 생성하게 되는 것이 바로 싱글톤의 가장 큰 특징입니다.


이 인스턴스가 이미 만들어져 있다면 그 인스턴스를 그대로 돌려주도록 구현되어 있습니다. 자세한 내용은 밑의 구현부에서 확인할 수 있습니다.


<CChocolateBoiler.cpp>

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
52
53
54
55
56
57
58
59
60
#include "CChocolateBoiler.h"
 
CChocolateBoiler *CChocolateBoiler::mChocolateInstance = NULL;
 
CChocolateBoiler* CChocolateBoiler::GetInstance() {
    if (NULL == mChocolateInstance)
    {
        mChocolateInstance = new CChocolateBoiler();
    }
    return mChocolateInstance;
}
 
bool CChocolateBoiler::IsEmpty()
{
    return bEmpty;
}
 
bool CChocolateBoiler::IsBoiled()
{
    return bBoiled;
}
 
void CChocolateBoiler::Fill() {
    if (IsEmpty())
    {
        bEmpty = false;
        bBoiled = false;
        printf("Chocolate is filled.\n");
    }
    else
    {
        printf("Chocolate is already filled.\n");
    }
}
 
void CChocolateBoiler::Drain()
{
    if(!IsEmpty() && IsBoiled())
    {
        bEmpty = true;
        printf("Chocolate is going next step.\n");
    }
    else
    {
        printf("Chocolate isn't ready to Drain.\n");
    }
}
 
void CChocolateBoiler::Boil()
{
    if!IsEmpty() && !IsBoiled() )
    {
        bBoiled = true;
        printf("Chocolate is Boiled.\n");
    }
    else
    {
        printf("Chocolate isn't ready to Boiled. Please Check Chocolate.\n");
    }
}
cs

 static 변수라, 전역에서 먼저 초기화를 시켜주게 됩니다.

GetInstance()를 통해서만 해당 인스턴스를 가지고 올 수 있습니다. GetInstance 함수에서, 초콜릿 보일러 객체가 선언되어 있지 않다면, 새로운 객체를 생성해 주고, 그렇지 않으면 instance를 반환시켜줍니다. 그리고 나머지 구현된 함수는, 초콜릿 보일러를 통해 초콜릿 재료를 만들 때 재료 확인을 위해 필요한 함수들입니다.


그러면, main에서 위 초콜릿보일러 객체를 선언 후 결과를 확인해 보겠습니다.

<main.cpp>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "CChocolateBoiler.h"
 
int main() {
    
    // 초콜릿 보일러 인스턴스를 가지고 옴
    CChocolateBoiler *chocolateBoiler = CChocolateBoiler::GetInstance();
 
    chocolateBoiler->Fill();
    chocolateBoiler->Fill();
    chocolateBoiler->Drain();
    chocolateBoiler->Boil();
    
    // 이미 만들어진 초콜릿 보일러 인스턴스를 가지고 
    CChocolateBoiler *chocolateBoiler2 = CChocolateBoiler::GetInstance();
 
    chocolateBoiler2->Drain();
 
    return 0;
}
cs

Fill()을 두 번 부르면, 이미 재료가 채워 졌기 때문에 더 이상 재료를 채우지 않습니다. 그리고 재료를 끓이지 않았기 때문에, 첫 Drain()은 실행되지 않고, Boil() 함수 실행 후, Drain()을 불렀을 때 재료가 다음 단계로 넘어가게 됩니다.


단 하나 밖에 없는 객체이기 때문에 위와 같이 chocolateBoiler2에서 실행을 해도 이전에 chocolateBoiler가 하던 일을 그대로 이어받아 진행하게 됩니다.

 이미 chocolateBoiler에서 Boil()까지 진행되었으니, 다음 chocolateBoiler2에서 Drain() 공정을 돌릴 수 있는 조건이 채워져 Drain()이 성공적으로 이루어지겠죠?


이 함수들을 실행 시키게 되면,


위 스크린샷과 같이 실행되는 것을 확인할 수 있습니다.



3. 정리

싱글톤 패턴을 적용하게 되면, 한 애플리케이션에 최대 하나의 인스턴스를 생성할 수 있습니다. 그리고 이 유일한 인스턴스를 어디에서든 접근가능하도록 만들 수 있습니다. 그렇게 구현되기 위해 Static 함수인 GetInstance()를 통해서만 생성, 접근 가능한 구조로 구현되어 있습니다. 


정말 자주 쓰이는 디자인 패턴이라, 다른 디자인 패턴보다도 이 싱글톤 패턴을 아는 것이 매우 중요하다고 생각합니다.



많이 부족한 게시글을 읽어주셔서 감사합니다. 많이 도움이 되었길 바랍니다. 언제나 틀린 부분이 있으면 지적해주시면 감사하겠습니다.


최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함