특정 클래스의 인스턴스(=객체)를 1개만 생성하도록 제한하고, 이를 공유하는 방법으로, 생성자를 private으로 하고, 자기 자신을 받는 함수를 만들어서 자기 자신의 객체를 반환하는 클래스를 의미
예를 들어 여러 프로젝트에서 공통적으로 접근해서 일관된 내용의 코드를 출력해야하는데, 신규 객체를 계속 생성하면 이전 내용이 삭제되기 때문에 이를 방지하는 목적으로 싱글톤 패턴을 사용한다.
정적 싱글톤 패턴 사용 코드 예제
class SingletonClass {
private:
static SingletonClass instance; // 싱글톤 클래스라는 타입(=자기자신의 타입)으로 선언한 멤버 변수
SingletonClass() {}
~SingletonClass() {}
public:
static SingletonClass& getInstance() { return instance; } // new 연산자를 사용하지 않은 이유는 정적 할당으로 객체를 생성했기 때문
void ShowMessage() { cout << "싱글톤 패턴" << endl; }
};
SingletonClass SingletonClass::instance; // static 변수는 외부에서 초기화가 가능
void main() {
// 일반적으로 클래스의 함수 호출하기
// SingletonClass sg; // 객체 생성
// sg.ShowMessage(); 멤버 함수 호출하여 메세지 출력
// SingletonClass::getInstance(); // getInstance 멤버함수를 통한 싱글톤 클래스 객체 생성
SingletonClass::getInstance().ShowMessage(); // 싱글톤 패턴의 객체를 생성해서 함수 접근 후 호출 및 출력
}
다만, 싱글톤 패턴은 외부가 아닌 내부에서 객체를 생성하기 때문에 외부에서 전역객체가 생성되기 전에 참조하게 되어버리면 오류가 발생할 수 있다.
이러한 문제를 해결하기 위해, 늦은 초기화 기법을 사용한다.
즉, 객체의 생성 시점을 조절하여 멤버 함수가 호출되는 시점(=인스턴스가 선언되었을 때)에 객체가 생성되도록 함으로써 보다 안정적으로 코드를 사용할 수 있다.
이러한 방법을 동적 싱글톤 패턴이라고도 부른다.
동적 싱글톤 패턴 코드 예제
class SingletonClass {
private:
static SingletonClass *instance; // 정적할당이 아닌 동적인 new 연산자로 객체를 생성하여 주소값을 리턴해야하기에 포인터로 변수 선언
SingletonClass() {}
~SingletonClass() {}
public:
static SingletonClass* getInstance() {
if (!instance) { // instance가 null이면
instance = new SingletonClass(); // new 연산자로 객체 생성
} // 그렇지 않다면 (= instance 객체가 생성되어져 있다면)
return instance; // 기존에 생성된 instance 객체 반환
}
void ShowMessage() { cout << "싱글톤 패턴" << endl; }
};
SingletonClass* SingletonClass::instance = NULL; // 늦은 초기화
void main() {
SingletonClass::getInstance()->ShowMessage(); // 생성된 getInstace가 포인터이기 때문에 함수는 간접참조로 호출
}