티스토리 뷰
오늘은 싱글톤 패턴에 대해 소개해보려고 합니다.
제가 제일 처음 접한 디자인패턴이라, 여러모로 특별한 의미를 가지는 디자인 패턴이고, 제가 생각하기엔, 가장 많이 활용되는 디자인패턴이 아닌가 싶습니다.
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()를 통해서만 생성, 접근 가능한 구조로 구현되어 있습니다.
정말 자주 쓰이는 디자인 패턴이라, 다른 디자인 패턴보다도 이 싱글톤 패턴을 아는 것이 매우 중요하다고 생각합니다.
많이 부족한 게시글을 읽어주셔서 감사합니다. 많이 도움이 되었길 바랍니다. 언제나 틀린 부분이 있으면 지적해주시면 감사하겠습니다.
'Design Pattern' 카테고리의 다른 글
디자인 패턴 - 7. Facade Pattern (0) | 2018.10.15 |
---|---|
디자인 패턴 - 6. Adapter Pattern (0) | 2018.10.12 |
디자인 패턴 - 5. Command Pattern (0) | 2018.10.09 |
디자인 패턴 - 2. Observer Pattern (1) | 2018.09.16 |
디자인 패턴 - 1. Strategy Pattern (0) | 2018.09.10 |