싱글턴 패턴은 오직 한 개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공한다.
싱글턴 패턴의 특징
1. 오직 한 개의 클래스 인스턴스만 갖도록 보장
시스템에서 하나만 있어야 하는 객체는 GameManager나 파일 시스템 클래스와 같은 것들이 있다.
2. 전역 접근점을 제공 (전역 변수로써 기능)
class FileSystem {
public:
static FileSystem& instance() {
// 게으른 초기화
if (instance_ == NULL) {
instance_ = new FileSystem();
}
return *instance_;
private:
FileSystem() {}
static FileSystem* instance_;
};
class FileSystem{
public:
static FileSystem& instance() {
static FileSystem *instance = new FileSystem();
return *instance;
}
private:
FileSystem() {}
};
어디서든 필요할 때 마다 instance 함수로 클래스 인스턴스를 얻을 수 있다. (인스턴스 정보를 수정할 수 있다.)
FileSystem instance = FileSystem.instance()
3. 한 번도 사용하지 않는다면 아예 인스턴스를 생성하지 않는다.
ㄴ 싱글턴은 처음 사용될 때 초기화되므로 게임 내에서 사용되지 않는다면 초기화 되지 않는다. (메모리 사용량 감소)
4. 런타임에 초기화된다.
ㄴ 컴파일러에서 정적 변수 초기화 순서를 보장해주지 않기 때문에 정적 변수 사이 안전한 의존 관계를 만들 수 없는데
게으른 초기화는 이런 문제를 해결해 준다.
5. 싱글톤을 상속하여 사용할 수도 있다.
ㄴ 싱글턴 객체가 플랫폼 별로 다르게 정의되어야 하는 경우 사용할 수 있음
FileSystem& FileSystem::instance() { // filesystem을 싱글턴으로 만든다.
#if PLATFORM == PLAYSTATION3
static FileSystem *instance = new PS3FileSystem(); // FileSystem을 상속받는 ps3 전용 filesystem
#elif PLATFORM == WII
static FileSystem *instance = new WiiFileSystem();
#endif
return *instance;
}
단점
싱글턴 인스턴스는 어디에서든 접근 할 수 있기 때문에 전역 변수로써 기능한다.
= 전역변수의 단점
1. 멀티 스레딩 같은 동시성 프로그래밍에 알맞지 않다.
2. 전역 변수는 커플링을 조장한다.
3. 전역 변수는 코드를 이해하기 어렵다. (어디서든 상태를 변경할 수 있기 때문에 변경하는 부분을 찾기 어렵다.)
4. 싱글턴은 문제가 하나뿐일 때도 두 가지 문제를 풀려고 한다.
ㄴ 오직 한 개의 인스턴스를 가지는 기능과 전역 접근 기능 중 어느 한 가지 기능만 따로 사용할 수는 없다.
5. 게으른 초기화는 제어할 수 없다.
게임 런타임중, 오디오 시스템 초기화나 파일 시스템 초기화가 일어나면 프레임이 떨어질 수 있다.
게임에서는 메모리 단편화를 막기 위해 힙에 메모리를 할당하는 방식을 세밀하게 제어하는데, 이 때문에 힙 어디에 메모리를 할당할지를 제어할 수 있도록 적절한 초기화 시점을 찾아야 한다.
싱글턴 대신 정적 클래스를 사용하고 정적 함수를 사용하는 것이 더 간단할 수 있다. 이러면 instance() 함수를 호출할 필요도 없다. 클래스이름::함수() 로 바로 함수를 호출할 수 있다.
싱글턴의 대안
1. 한 개의 인스턴스만 보장하는 기능
ㄴ 인스턴스가 이미 생성되었는지 여부를 단언문으로 확인
ㄴ ex) assert(!instantiated_);
2. 인스턴스에 쉽게 접근하는 기능
ㄴ 방법 1. 객체를 필요로 하는 함수에 인수로 넘겨주기
ㄴ 방법 2. 상위 클래스로부터 얻기
상위 클래스에 객체를 반환하는 함수를 만든다. 함수를 protected로 선언하면 그 클래스를 상속받은 코드에서만 객체에 접근할 수 있게 된다.
ㄴ 방법 3. 이미 전역인 객체로부터 얻기
전역에서 접근할 수 있는 Game 클래스가 있다고 가정하면 Log, FileSystem, Audio, Player를 각각 싱글턴으로 만드는 대신
Game 객체 하나만 싱글턴으로 만들고, Log, FileSystem, Audio, Player는 Game 클래스의 멤버 객체로 만드는 방법을 사용할 수 있다.
'읽은 책 > 게임 프로그래밍 패턴' 카테고리의 다른 글
8. 순서 패턴 - 이중 버퍼 (0) | 2022.07.15 |
---|---|
7. 디자인 패턴 - 상태(state) (0) | 2022.07.15 |
5. 디자인 패턴 - 프로토타입 (0) | 2022.07.13 |
4. 디자인 패턴 - 관찰자, 감시자(observer) (0) | 2022.07.13 |
3. 디자인 패턴 - 경량(flyweight) (0) | 2022.07.13 |