[디자인 패턴] #5_싱글턴 패턴, Singleton Pattern
게임 디자인 패턴 중 "싱글턴 패턴(Singleton Pattern)"에 대해 알아보겠습니다.
"게임 프로그래밍 패턴"의 6 항목, "싱글턴"에 해당하는 내용입니다.
싱글턴 패턴
오직 한 개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공한다.
- GoF의 디자인 패턴 81pg
"싱글턴 패턴"은 오직 한 개의 클래스 인스턴스만이 존재하도록 보장하고, 이에 대한 전역적인 접근을 허용하는 디자인 패턴입니다.
자세한 내용을 살펴보도록 합시다!
1. 오직 한 개의 인스턴스만 갖도록 보장
먼저, "싱글톤 패턴"의 두 가지 특징 중 첫 번째 특징을 살펴보겠습니다.
"오직 한 개의 클래스 인스턴스만을 보장" 하는 "싱글턴 패턴"은 파일 시스템 API를 래핑 하는 클래스 등의 "비동기 프로그래밍"을 필요로 하는 곳에서 주로 활용됩니다.
* 여기서, "비동기 프로그래밍"은 여러가지 Task들을 동시간에 처리하는 프로그래밍 방식을 얘기합니다.
그렇다면, 왜 비동기 프로그래밍을 수행하는 "파일 시스템" 관련한 클래스에 "싱글턴 패턴"이 활용 될까요?
예를 들면, 파일을 생성하거나 내용을 변경하고자 하는 한쪽이 있는 반면에, 해당 파일을 삭제 하려고하는 다른 한 쪽이 존재할 수 있겠죠? "비동기 프로그래밍"으로 여러 작업들을 동시에 처리하고 조율하니까요!
이때, "싱글턴 패턴"을 적용하여 "파일 시스템"클래스의 인스턴스를 오직 한 개만 생성하여, 이곳저곳에서 생성하지 못하도록 강제하여 파일 관련 작업들의 "비동기 처리"를 성공적으로 수행할 수 있겠죠!
2. 전역 접근점 제공
class FileSystem
{
public:
static FileSystem& GetInstance()
{
// 게으른 초기화
if(instance == NULL)
{
instance = new FileSystem();
}
return *instance;
}
private:
// private 영역에 생성자 선언!
FileSystem(){}
// static 선언된 인스턴스
static FileSystem* instance;
};
다음으로, "싱글턴 패턴"의 두 번째 특징에 대해서 알아보겠습니다.
파일 시스템 클래스의 경우 여러 시스템에서 접근하겠죠.
따라서, 인스턴스가 오직 한 개만 생성 가능할 수 있음에도 불구하고, 전역적 접근점을 제공해야 합니다.
이때, "싱글턴 패턴"은 하나의 인스턴스만 생성하는 것에 더해서, 해당 인스턴스를 전역에서 접근할 수 있도록 정적 메서드를 제공하고 있습니다.
위 코드를 살펴보면, "GetInstance()" 정적 메서드는 정적 객체 "FileSystem* instance"를 반환하고 있는 것을 확인할 수 있습니다!
더불어, "FileSystem" 객체의 생성자는 private 영역에 선언하여 외부에서 "FileSystem" 객체의 인스턴스를 생성할 수 없겠죠.
정리하자면, "싱글턴 패턴"은 클래스의 생성자를 private 영역에 두어 인스턴스 생성을 한 개로 제한하고, 생성된 오직 한 개의 인스턴스는 public 영역에 선언한 정적 멤버 메서드를 통해 전역에서 접근할 수 있도록 하는 것입니다!
그렇다면, 왜 "싱글턴 패턴"을 사용하는지 자세히 살펴보죠!
1. Why? 성능 증가
"싱글턴 패턴"은 첫 사용에 초기화되며, 게임 내에서 전혀 사용하지 않으면 아예 초기화되지 않습니다!
앞서 살펴본 예제 코드에서 우리는 인스턴스의 게으른 초기화를 발견할 수 있었습니다!
따라서, 객체의 초기화와 함께 생성되는 인스턴스는 객체의 초기화 없이 생성되는 일은 없겠죠!
2. Why? 런타임에 초기화, 동적 바인딩
"싱글턴 패턴"은 static 변수가 갖는 자동 초기화 문제를 방지합니다!
알다시피, 컴파일러는 정적 멤버 변수를 main 문을 호출하기 전에 초기화합니다.
더불어, 컴파일러는 정적 변수들의 초기화 순서도 보장하지 않죠!
이때, "싱글턴 패턴"은 게으른 초기화를 통해 이러한 문제들을 해결할 수 있습니다.
3. Why? 상속 가능한 싱글턴
class FileSystem
{
public:
FileSystem& GetInstance();
public:
virtual ~FileSystem();
virtual string readFile(string path) = 0;
virtual void writeFile(string path, string contents) = 0;
private:
FileSystem(){}
FileSystem* instance;
};
// 플랫폼 별 하위 클래스
1. PS3
class PS3FileSystem : public FileSystem
{
public:
virtual string readFile(string path)
{ //... }
virtual void writeFile(string path, string contents)
{ //... }
};
2. Wii
class WiiFileSystem : public FileSystem
{
//...
};
"싱글턴 패턴"의 강점은 상속이 가능하다는 것입니다.
위 예제 코드는 우리가 앞서 살펴본 싱글턴 패턴을 활용한 "FileSystem" 클래스를 "PS3", 그리고 "Wii" 등의 다양한 크로스 플랫폼들에서 "싱글턴 패턴"의 상속 기능을 활용한 예제입니다.
단점
그렇다면, "싱글턴 패턴"의 단점은 무엇일까요?
"싱글턴 패턴"의 단점은 대게 "전역 변수"와 관련이 있습니다.
1. 코드 가독성 저하
2. 커플링 조장
3. 멀티스레딩 프로그래밍에 부적합 ( 교착 상태, 경쟁 상태 등)
'언어 > 디자인 패턴' 카테고리의 다른 글
[디자인 패턴]#7_이중 버퍼, Double Buffer (0) | 2022.08.21 |
---|---|
[디자인 패턴]#6_상태 패턴, State Pattern (1) | 2022.08.20 |
[디자인 패턴]#4_프로토타입 패턴, Prototype Pattern (0) | 2022.07.22 |
[디자인 패턴]#3_관찰자 패턴, Observer Pattern (0) | 2022.07.15 |
[디자인 패턴]#2_경량 패턴, Flyweight Pattern (0) | 2022.07.10 |