싱글톤 패턴(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();
};
댓글
댓글 쓰기