싱글톤 패턴(Singleton Pattern)
참고) 싱글톤의 종류가 여러가지이다. 최하단에 템플릿 다이나믹 싱글톤만 보면 될 것
* 싱글톤 패턴 개념
- 가장 기본적인 디자인 패턴(32가지 패턴 중 편리하지만 많은 문제를 가짐)
* 싱글톤 사용시 생기는 문제에 대한 예시(핵심: 한 개의 인스턴스 + 전역 접근)
1) 게임내 모듈 진단 정보를 Log로 남기고 싶다.
2) 모든 함수에 Log클래스 인스턴스를 추가하면 코드가 난잡해진다.
3) 이를 해결하는 가장 간단한 해결책이 Log클래스를 싱글톤으로 만들어 직업 Log클래스에 접근해 인스턴스를 얻게 할 수 있다.
4) 단, Log 객체를 하나 밖에 못만드는 제한이 생긴다.
5) 각 개발팀이 필요한 로그를 남기려 할때 로그 파일이 뒤죽박죽 섞여 버린다.
6) 전역 접근의 장점이 한 개의 인스턴스 생성이라는 단점을 발생시켰다.
* Basic Singleton(기본 싱글톤)
< 단점 >
1) static 클래스 멤버 변수는 static 전역 변수처럼 main함수 호출 이전에 초기화 되어 사용 여부에 상관 없이 메모리를 사용한다.
2) 정적개체이므로 다른 전역 객체 생성자에서 참조하려는 경우 문제 발생
* Dynamic Singleton(다이나믹 싱글톤)
- 기본 싱글톤의 문제를 늦은 초기화(게으른 초기화)를 사용하여 피한 것
- 다이나믹 싱글콘은 최초 GetInstance()를 호출하는 시점에 생성 된다.
- new로 동적 메모리 할당을 하였고, 해제를 위에 atexit 함수나, 다른 전역 객체의 소멸자 이용
* static Local Singleton(스테틱 지역 싱글톤)
- static 변수를 지역으로 사용한 싱글톤
- 해당 함수를 호출하는 시점에 초기화와 생성(객체를 사용하지 않으면 생성 x)
- 생성되면 static객체이므로 프로그램 종료까지 남아 있다 종료 시 소멸
* Phoenix Singleton(피닉스 싱글톤)
- 싱글톤 참조시 해당 객체가 소멸되었다면 다시 되살림
- 헤더 <new><stdlib.h>를 추가해야함
- 강력한 기능을 가지지만 잘 쓰지 않는다
Template Singleton(템플릿 싱글톤) <= 가장 대세(게임 포폴 제작에 사용) *넘모조아!*
- 상속만 해주면 싱글톤 기능을 활용할 가능(상속 받은 모든 객체가 싱글톤 역할)
- 일일이 모든 코드에 싱글톤 소스를 쓰지 않아도 되는 편리
- 다이나믹 싱글톤과 합쳐 Template Dynamic Singleton 을 사용
* 싱글톤 패턴 개념
- 가장 기본적인 디자인 패턴(32가지 패턴 중 편리하지만 많은 문제를 가짐)
- 오직 한 개의 클래스 인스턴스만을 갖도록 제한(인스턴스가 여러개일때 제대로 작동하지 않는 경우가 종종 있다)
- 전역적인 접근점을 제공
- 싱글톤 클래스는 맨 처음 생성된 이후로 프로그램 종료까지 단 한번 생성(메모리 누수 문제 발생이 낮다)
- 싱글톤 클래스는 맨 처음 생성된 이후로 프로그램 종료까지 단 한번 생성(메모리 누수 문제 발생이 낮다)
* 싱글톤 사용 이유(핵심: 한 개의 인스턴스 + 전역 접근)
1) 번거로운 인수 없이 전역에서 접근 가능
2) 한 번도 사용하지 않으면 인스턴스를 생성하지 않는다.
2) 한 번도 사용하지 않으면 인스턴스를 생성하지 않는다.
3) 늦은 초기화로 런타임에 초기화 가능
4) 싱글톤을 상속할 수 있다.
* 싱글톤의 문제: 클래스로 캡슐화된 전역 변수 이다. 즉, 전역 상태의 문제를 해결 할 수 없다.
* 전역 변수의 문제
1) 코드를 이해하기 어렵게 한다(소스코드 전역에서 찾아 살펴 봐야 하기 때문)
* 전역 변수의 문제
1) 코드를 이해하기 어렵게 한다(소스코드 전역에서 찾아 살펴 봐야 하기 때문)
2) 커플링을 조장(인스턴스에 대한 접근을 통제하여 커플링을 제한할 수 있다)
3) 멀티스레딩 같은 동시성 프로그래밍에 맞지 않다.
(전역변수 => 모든 스레드가 볼 수 있다 => 다른 스레드가 전역 데이터에 하는 작업을 모를 수 있다 = > 스레드 동기화 버그 생성)
(전역변수 => 모든 스레드가 볼 수 있다 => 다른 스레드가 전역 데이터에 하는 작업을 모를 수 있다 = > 스레드 동기화 버그 생성)
4) 늦은 초기화(게으른 초기화)는 제어할 수 없다.(전투도중 초기화로 프레임 드랍 발생)
* 싱글톤 사용시 생기는 문제에 대한 예시(핵심: 한 개의 인스턴스 + 전역 접근)
1) 게임내 모듈 진단 정보를 Log로 남기고 싶다.
2) 모든 함수에 Log클래스 인스턴스를 추가하면 코드가 난잡해진다.
3) 이를 해결하는 가장 간단한 해결책이 Log클래스를 싱글톤으로 만들어 직업 Log클래스에 접근해 인스턴스를 얻게 할 수 있다.
4) 단, Log 객체를 하나 밖에 못만드는 제한이 생긴다.
5) 각 개발팀이 필요한 로그를 남기려 할때 로그 파일이 뒤죽박죽 섞여 버린다.
6) 전역 접근의 장점이 한 개의 인스턴스 생성이라는 단점을 발생시켰다.
* Basic Singleton(기본 싱글톤)
< 단점 >
1) static 클래스 멤버 변수는 static 전역 변수처럼 main함수 호출 이전에 초기화 되어 사용 여부에 상관 없이 메모리를 사용한다.
2) 정적개체이므로 다른 전역 객체 생성자에서 참조하려는 경우 문제 발생
class Singleton{private: Singleton(){}; Singleton(const Singleton& other); static Singleton instance;public: static Singleton* GetInstance() { return instance; }};Singleton* Singleton::instance = nullptr;//1< 사용법Singleton::GetInstance()* Dynamic Singleton(다이나믹 싱글톤)
- 기본 싱글톤의 문제를 늦은 초기화(게으른 초기화)를 사용하여 피한 것
- 다이나믹 싱글콘은 최초 GetInstance()를 호출하는 시점에 생성 된다.
- new로 동적 메모리 할당을 하였고, 해제를 위에 atexit 함수나, 다른 전역 객체의 소멸자 이용
class DynamicSingleton{private: DynamicSingleton() {}; DynamicSingleton(const DynamicSingleton& other); ~DynamicSingleton() {}; static DynamicSingleton* instance;public: static DynamicSingleton* GetInstance() { if(instance == NULL) instance = new DynamicSingleton(); return instance; }};DynamicSingleton* DynamicSingleton::instance = nullptr;//!< 사용법 DynamicSingleton::GetInstance()* static Local Singleton(스테틱 지역 싱글톤)
- static 변수를 지역으로 사용한 싱글톤
- 해당 함수를 호출하는 시점에 초기화와 생성(객체를 사용하지 않으면 생성 x)
- 생성되면 static객체이므로 프로그램 종료까지 남아 있다 종료 시 소멸
//1. 첫번째 방식(포인터 없이 주소값 받기)class LocalStaticSingleton{private: LocalStaticSingleton(); LocalStaticSingleton(const LocalStaticSingleton& other); ~LocalStaticSingleton();public: static LocalStaticSingleton& GetInstance() { static LocalStaticSingleton ins; return ins; }};//2. 두번째 방식(포인터 사용)class LocalStaticSingleton{private: LocalStaticSingleton(); LocalStaticSingleton(const LocalStaticSingleton& other); ~LocalStaticSingleton();public: static LocalStaticSingleton* GetInstance() { static LocalStaticSingleton ins; return &ins; }};* Phoenix Singleton(피닉스 싱글톤)
- 싱글톤 참조시 해당 객체가 소멸되었다면 다시 되살림
- 헤더 <new><stdlib.h>를 추가해야함
- 강력한 기능을 가지지만 잘 쓰지 않는다
class PhoenixSingleton{private: static bool bDestroyed; static PhoenixSingleton* pIns; PhoenixSingleton() {}; PhoenixSingleton(const PhoenixSingleton& other); ~PhoenixSingleton() { bDestroyed = true; } static void Create() { static PhoenixSingleton ins; pIns = &ins; } static void KillPheonix() { pIns->~PhoenixSingleton(); }public: static PhoenixSingleton& GetInstance() { if (bDestroyed) { new(pIns) PhoenixSingleton; atexit(KillPheonix); bDestroyed = false; } else if (pIns == NULL) { Create(); } return *pIns; }};//!< 사용 방법bool PhoenixSingleton::bDestroyed = false;PhoenixSingleton* PhoenixSingleton::pIns = NULL;Template Singleton(템플릿 싱글톤) <= 가장 대세(게임 포폴 제작에 사용) *넘모조아!*
- 상속만 해주면 싱글톤 기능을 활용할 가능(상속 받은 모든 객체가 싱글톤 역할)
- 일일이 모든 코드에 싱글톤 소스를 쓰지 않아도 되는 편리
- 다이나믹 싱글톤과 합쳐 Template Dynamic Singleton 을 사용
template < typename T >class TemplateSingleton{protected: TemplateSingleton() { } virtual ~TemplateSingleton() { }public: static T * GetInstance() { if (m_pInstance == NULL) m_pInstance = new T; return m_pInstance; }; static void DestroyInstance() { if (m_pInstance) { delete m_pInstance; m_pInstance = NULL; } };private: static T * m_pInstance;};template <typename T> T * TemplateSingleton<T>::m_pInstance = 0;//!< 사용법class CObject : public TemplateSingleton<cobject>{public: CObject(); ~CObject();};
댓글
댓글 쓰기