singleton 클래스 이야기(1)
singleton 클래스를 디자인하고 만드는 것에 대해 여러 글을 읽어 보았습니다. 그래서 이번에 정리 차원에서 이래 저래 검토해 본 “singleton 클래스 이야기”라는 글을 써 볼까 합니다. 본 글에서는 App라는 클래스(application 혹은 process의 정보를 제공하는 클래스)를 예를 들면서 설명을 해 보겠습니다.
위키피디아에서는 singleton을 다음과 같이 정의하고 있습니다. 즉 쉽게 말해서 객체(instance)가 하나뿐인 클래스라고 쉽게 생각하면 됩니다.
In software engineering, the singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object.
여기에서 몇가지 전제 조건이 생기게 됩니다.
-
(A) instance가 함부로 생성되지 않도록 constrcutor 및 destructor를 public으로 선언하지 않고 private로 선언한다.
-
(B) instance의 복사가 허용되지 않도록 copy constructor 및 assign operator를 public으로 선언하지 않고 private로 선언한다.
-
(C) instance의 interface를 제공하기 위해 instance()라는 메소드를 public으로 제공한다.
상기 조건을 이용해서 App라는 클래스를 만들어 보겠습니다.
class App {
private: // private constructor and destructor prevent creating and deleting object. // (A)
App();
virtual ~App();
private: // private copy constructor and assign operator prevent copying object. // (B)
App(const App&);
const App& operator = (const App&);
public: // public instance methods supports class reference access. // (C)
static App& instance() {
static App app;
return app;
}
};
참고로 boost::noncopyable 이라는 클래스를 상속받아서 상기 요구 사항중 (B)를 해결할 수도 있습니다.
-
(A)를 private(protected가 아닌)으로 선언을 하는 것은 App 클래스의 상속을 허용하지 않기 위함입니다. singleton 클래스를 상속하면 안되는 이유는 추후에 다시 설명하겠습니다.
-
(B)를 public으로 선언하지 않은 이유는 객체의 복사를 방지하기 위해서입니다. (B)를 private으로 하느냐 protected로 하느냐는 별 의미가 없습니다. 어차피 클래스 상속이 (A)에 의해 차단이 되므로.
-
(C)에서는 app라는 object를 static local로 선언을 하였습니다. static local로 선언하는 것과 static global(member)로 선언하는 방식 2가지가 있을 수 있는데, 각각 장단점이 있습니다. 이는 추후에 자세한 설명을 하도록 하겠습니다.
설계된 App class를 이용해서 클래스에 접근을 해 보도록 하겠습니다. 의도하는 바대로 compile error가 나면서 객체의 외부 생성 및 복사를 방지함을 알 수가 있습니다.
void testA()
{
App app; // 'App::App' : cannot access private member declared in class 'App'
// 'App::~App' : cannot access private member declared in class 'App'
};
void testB(App* app1, App* app2)
{
*app1 = *app2; // 'App::operator =' : cannot access private member declared in class 'App'
}
void testC()
{
App& app = App::instance(); // compile ok
}
#include <boost/noncopyable.hpp>
class App : boost::noncopyable {
private: // private constructor and destructor prevent creating and deleting object. // (A)
App();
virtual ~App();
public:
static App& instance() {
static App app;
return app;
}
};
출처 : gilgil.net