2016년 4월 1일 금요일

[디자인패턴] 싱글톤 패턴 (Singleton Pattern)

싱글톤 패턴

디자인 패턴이란 개발자들의 개발 방법( 즉, 패턴 )을 조사하여 정리한 것으로 약 25개가 존재한다.

싱글톤 패턴이란 디자인 패턴에서 가장 많이 쓰이는 패턴 중 하나이다.

 하나의 프로그램 내에서 하나의 인스턴스만 만들어지고 어디서든지 그 인스턴스에 접근할 수 있도록 만든 패턴이다.
 객체를 메모리에 한번만 올려 사용하는 패턴으로 클래스에 하나만 존재하고 주로 매니저급 관리자 클래스에서 사용된다. 관리자로써 필요한 애들만 매니저로 만들어서 사용하는 것이다. 싱글톤을 많이 사용하면 뒤엉킨 코드 즉 스파게티 코드가 되어 문제가 된다.

 클래스의 공용으로 쓰이는 것이므로 남발 할 수 없고, 메모리 관리자를 쓰게되면 할당할 때마다 포인터를 할당하는 스마트 포인터가 된다. 즉, 자기가 알아서 지워줄때를 판단한다. 

static을 클래스에 넣으면 반드시 전역에서 초기화 해줘야하고, 클래스 전역에서 쓸 수 있다.

그럼 이제 싱글톤 패턴에 대해 보겠다.

  1. class cSingleton  
  2. {  
  3. private:  
  4.     static cSingleton* m_pInstance;     // 멤버 변수  
  5. private:  
  6.     cSingleton(void);                   // 생성자 소멸자  
  7.     virtual ~cSingleton(void);  
  8. public:  
  9.     static cSingleton GetInstance(void// 멤버 함수  
  10.     {  
  11.         if(m_pInstance == NULL)  
  12.         {  
  13.             m_pInstance = new cSingleton;  
  14.         }  
  15.         return m_pInstance;  
  16.     }  
  17.     void Destroy(void)  
  18.     {  
  19.         if(m_pInstance)  
  20.         {  
  21.             delete m_pInstance;  
  22.             m_pInstance = NULL;  
  23.         }  
  24.     }  
  25. };  


 생성자 소멸자를 private으로 바꿔 다른 클래스에서 생성자를 호출하지 못하게 한다.

static의 멤버 변수와 멤버 함수를 만든다. 이름을 Instance 라고 만든 이유는 객체가 메모리 공간 안에 잡혔다는 것을 표현하기 위해서 이다. 멤버 변수는 동적할당을 위한 포인터 역할을 하며, 멤버함수는 함수가 소속된 클래스를 객체화 하는 일을 한다.

static의 멤버 변수는 cpp에서 반드시 아래와 같이 초기화 해줘야 한다.

cSingleton* cSingleton::m_pInstance = NULL ; 

 그리고 멤버 함수에서 할당된 메모리를 해제할 Destroy함수를 만든다. 이 클래스를 사용한 후 반드시 이 함수를 호출해
메모리를 해제해줘야 한다.



보통 클래스를 객체화 할 때

 포인터로 선언한 후 new라는 키워드를 통해 생성한다. 이럴경우 클래스의 인스턴스가 동적할당 되었기 때문에 Heap 영역에 올라가고, 그 인스턴스를 가리키는 변수는 stack 영역에 생기게 된다. 객체를 Heap 에 올리는 작업 자체가 시간이 오래 걸리는 일이기 때문에 자주 사용되는 객체, 혹은 어떠한 작업을 관리하는 매니저 같은 객체를 생성할때는 한번만 생성(Heap 에 한번만 올림)하면 stack에서 같은 객체를 가리키게 한다.

 이러한 방식이 싱글톤이고, 싱글톤으로 인해 객체가 Heap으로 올라갈때의 시간과 메모리를 줄일 수 있다.


싱글톤 패턴을 탬플릿으로 만들면 굉장히 사용하기에 편하다.
탬플릿 함수와 탬플릿 클래스에 대해 공부한 사람이라면 누구나 만들 수 있을 것이다.

// Singleton class
#pragma once

template <typename T>
class CSingleton
{
public:
  static T * InstancePtr()
  {
    if( ms_Instance == NULL ) ms_Instance = new T;
    return ms_Instance;
  };
  static T & Instance()
  {
    if(ms_Instance == NULL) ms_Instance = new T;
    return *ms_Instance;
  };
  static void DestroyInstance()
  {
    delete ms_Instance;
    ms_Instance = NULL;
  };

private:
  static T * ms_Instance;
};

template<typename T> T* CSingleton<T>::ms_Instance = 0;

#include "stdafx.h"
#include <iostream>

#include "CSingleton.h"

class CObject : public CSingleton<CObject>
{
public:
  CObject() : m_nValue(10) {}
  ~CObject();

  int m_nValue;
  int GetValue() { return m_nValue; }
};

#define TIME CObject::Instance()

int _tmain(int argc, _TCHAR* argv[])
{
  int time = TIME.GetTime();

  return 0;
}

댓글 없음:

댓글 쓰기

[Effective C++] 항목 30 : 인라인 함수는 미주알고주알 따져서 이해해 두자.

인라인 함수를 사용하면 컴파일러가 함수 본문에 대해 문맥별 최적화를 걸기가 용이해집니다. 인라인 함수의 아이디어는  함수 호출문을 그 함수의 본문으로 바꿔치기하자는 것  남발했다가는 코드의 크기가 커질 게 뻔하다. 인라인 함수로 부풀려진 ...