'패턴'에 해당되는 글 1건

  1. 2007.11.30 [GoF] Singleton pattern 싱글턴 패턴 2

[GoF] Singleton pattern 싱글턴 패턴

개발 2007. 11. 30. 15:38

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

날짜 : 2007-11-30

저자 : hanburn

 

1. Singleton 정의

  1.1 클래스 다이어그램

2. Singleton이 필요한곳

3. 구현

3.1 C++로 기본구현

3.2 Template 클래스화

3.3 template 화된 클래스 사용

4. FAQ

 

1. Singleton 정의

클래스의 인스턴스가 하나만 만들어 지고 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한패턴

 

  1.1 클래스 다이어그램

          

사용자 삽입 이미지

 

2. Singleton이 필요한 곳


스레드풀, 레지스트리 설정객체, 로그객체등

 

3. 구현

1.     ‘single instance’ 클래스에서 private static 멤버를 정의 한다.

2.     클래스에 static accessor를 정의한다.

3.     ‘lazy initialize(게으른 초기화 : 요청시 생성하는)’ accesor에 구현한다.

4.     생성자는 protected 또는 private로 정의한다.

 

 

  3.1 C++로 기본구현

class MyClass

{

public:

        static MyClass*        getInstance()          // 스레드의 안정성 문제가 있음

        {

               if( m_pInstance == 0 )

                       m_pInstance = new MyClass();

 

               return m_pInstance;

        }

 

        static releaseInstance()

        {

               delete m_pInstance;

               m_pInstance = 0;

        }

 

public:

        void print()

        {

               std::cout<< "print.." << std::endl;

        }

 

private:

        MyClass(){};           // private

 

        static MyClass*        m_pInstance;

};

 

MyClass* MyClass::m_pInstance = 0;

 

위의 C++로 구현된 부분에는 getInstance 부분에 멀티스레드에서 안정성이 보장이 않되는 문제가 있습니다. 멀티스레드를 고려해서 m_pInstance 를 포인터대신 m_Instance로 정적 변수로 사용하면 create on demand는 구현이 되지만 destroy on demand가 되지 않는 문제가 있습니다. 객체가 많은 리소스를 사용하고 시스템의 요구사항에 최소의 메모리 사용이 필요하다면 이것 또한 문제가 될 수 있습니다.

 

3.2 template 클래스화

 

template <class Obj>

class Singleton

{

public:

        static Obj*    getInstance()          // 스레드 안정성 문제 있음

        {

               if( m_pInstance == 0 )

               {

                       m_pInstance = new Obj();

               }

 

               return m_pInstance;

        }

 

        static releaseInstance()

        {

               delete m_pInstance;

               m_pInstance = 0;

        }

 

private:

        //Obj() {};            // 상속받는 곳에서 생성자를 private등으로 변경

 

        static Obj*    m_pInstance;

};

 

 

3.3 template화된 클래스 사용

 

#첫번째 방법

템플릿을 사용한 버전은 해당 클래스를 상속 받으면 Singleton 클래스로 된다. 한가지 상속을 받고 생성자를 private 또는 protected로 변경해주어야 한다. 이렇게 하면 컴파일시에 Singleton 템플릿 클래스의 getInstance()에서 new 부분에서 생성자가 private이라서 오류가 나므로 아래처럼 Singleton 클래스를 friend 클래스로 선언을 해주어야 한다.

 

<템플릿 클래스 상속을 통해서 정의>

class aa : public Singleton<aa>

{

friend class Singleton<aa>;   // 생성자가 private이므로

public:

        void print()

        {

               cout<< "aa::print" << endl;

        }

private:

        aa() {};       // 생성자는 private으로

};

 <사용시에는>

aa::getInstance()->print();   // getInstance 처음호출시 객체생성

// 기타작업

aa::releaseInstance(); // 자원을 해제할 경우 releaseInstance 호출

 

 # 두번째 방법

템플릿 버전을 아래처럼 사용하는 방법도 있다.


 <보통 정의된 클래스>

class bb

{

public:

        void print()

        {

               cout<< "bb::print" << endl;

        }

 

        int a;

};

 

 <사용시>

Singleton<bb>::getInstance()->print();

Singleton<bb>::getInstance()->a = 5;

int b = Singleton<bb>::getInstance()->a;

Singleton<bb>::releaseInstance();

 

두번째 방법은 기존에 정의되어 있는 클래스에 Singleton 템플릿 클래스가 Singleton 컨테이너(?)역할을 하게 된다. 물론 bb라는 클래스를 정의해서 사용할 수도 있게 되므로 bb 클래스자체가 Singleton이 되는 것은 아니다. 그저 사용시에 Singleton처럼 사용이 되는 것이다.

 

템플릿화된 클래스를 첫번째 방법처럼 상속을 통해서 사용할 수 있고, 두번째 방법처럼 사용할 수도 있다. 템플릿 정말 매력적이다.

 

 

4.  FAQ

Q : 정의대로 하나만 만들어 지고 어디서든지 접근 가능하다면 전역변수와의 차이점은 무엇인가요?

A : 전역변수는 프로그램이 시작될 때 객체가 생성되므로 객체의 라이프 싸이클(life-cycle)을 관리 할 수 없는 문제가 있음



: