페이지

2015년 1월 4일 일요일

Singleton Pattern (단일체 패턴)

Singleton Pattern

 프로그램상에 특정 형식의 개체가 N개 이하로만 생성됨을 보장해주는 방법 (보통 N은 1개일 경우가 많다.)

유용한 경우

1. 어떤 클래스의 객체가 최대 N개 이하로만 존재해야 할 때 이를 관리하기에 유용하다. 특히 N은 1일 경우가 많다.
2. 상속 관계에 놓인 클래스들에 대해 적제적으로 생성되는 객체의 최대 개수를 제한하고자 할 때 유용하다. 

장점

 1. 전역 변수 방식은 최대 N개 이하의 객체만 생성되어 존재한다는 사실을 확실히 보장할 수 없다. 특히 여러 사람이 공동 작업을 하는 경우에는 이런 문제가 발생될 소지가 크다. 반면 싱글턴 패턴 방식은 클래스 차원에서 최대 N개 까지만 객체가 생성되게 보장 해주기 때문에 이와 같은 문제는 걱정할 필요가 없다.
2. 전역 변수 방식으로 객체를 생성하기 위해서는 처음부터 객체를 초기화 시키기 위한 충분한 정보를 알고 있어야 한다. 반면 Singleton 패턴의 경우에는 CreateInstance() 클래스 멤버함수가 불려질 때까지는 객체가 생성되지 않으므로 처음부터 객체를 생성하기 위해 모든 정보를 알 필요가 없다.

통상적으로 N이 1개일 경우의 Singleton의 예제는 많고 그 사용법 또한 쉽다. 예전에 써놓은 예제 3가지는 아래 링크를 참조하기 바란다.

Singleton 예제 (Java)

Singleton과 일반 Instance 둘 다 지원되는 Class (C#)

C++ Singleton 을 지원하는 Template Class

 이번에는 조금 다른 예제를 하나 소개하고자 한다. 스타크래프트 게임에서 각 종족별로 Unit 수가 200개 이하로 제한되어 있다. 각 유닛별로 보급창 밥통의 요구하는 개수또한 다르다. 이것을 Singleton 을 이용하여 구현하면 유닛수 제한을 비교적 효율적으로 재밌게 구현이 가능하다. Singleton Class로 unit을 구현한 뒤 200개의 개체제한을 설정하고 생성되는 개체를 List로 관리한다.


#include "stdafx.h"
#include <iostream>
#include <windows.h>
 
class unit{
public:
    virtual int getUseCount() const = 0;
    static const int maxUnitCount = 200;
    static unit* CreateInstance()
    {
        return 0;
    }
    static void init()
    {
        unitcount = 0;
        memset(pUnit, 0x00, (sizeof(unit*) * unit::maxUnitCount));
    }
 
    static void DestroyUnit(unit* p)
    {
        for(int i = 0; i < unit::maxUnitCount; i++)
        {
            if(unit::pUnit[i] == p)
            {
                unit::unitcount -= p->getUseCount();
                std::cout << "Unit Count : " << unit::unitcount << std::endl;
                Sleep(300);
                if(unit::unitcount < 0) unit::unitcount = 0;
                delete p;
                unit::pUnit[i] = NULL;
                return ;
            }
        }
    }
 
    static void DestroyAllUnit()
    {
        for(int i = 0; i < unit::maxUnitCount; i++)
        {
            if(unit::pUnit[i])
            {
                unit::unitcount -= pUnit[i]->getUseCount();
                std::cout << "Unit Count : " << unit::unitcount << std::endl;
                Sleep(300);
                if(unit::unitcount < 0) unit::unitcount = 0;
                delete pUnit[i];
                unit::pUnit[i] = NULL;
            }
        }       
    }
 
protected:
    unit(){}
    unit(const unit& rhs){}
    static int unitcount;
    static unit* pUnit[unit::maxUnitCount];
};
 
unit*   unit::pUnit[unit::maxUnitCount];
int     unit::unitcount;
 
class marine : public unit
{
public:
    int getUseCount() const
    {
        return marine::useUnitCount;
    }
    static const int useUnitCount = 1;
    static unit* CreateInstance(){
        if(marine::useUnitCount + unit::unitcount > unit::maxUnitCount)
        {
            std::cout << "Want : " << marine::useUnitCount << " Now : " << unit::unitcount << std::endl;
            Sleep(300);
            return NULL;
        }
        else
        {
            unit::unitcount += marine::useUnitCount;
            std::cout << "Unit Count : " << unit::unitcount << std::endl;
            Sleep(300);
            for(int i = 0; i < unit::maxUnitCount; i++)
            {
                if(unit::pUnit[i] == NULL)
                {
                    unit::pUnit[i] = new marine;
                    return unit::pUnit[i];
                }
            }
        }
        return NULL;
    }
protected:
    marine(){}
    marine(const marine& rhs){}
};
 
class tank : public unit
{
public:
    int getUseCount() const
    {
        return tank::useUnitCount;
    }
    static const int useUnitCount = 2;
    static unit* CreateInstance(){
        if(tank::useUnitCount + unit::unitcount > unit::maxUnitCount)
        {
            std::cout << "Want : " << tank::useUnitCount << " Now : " << unit::unitcount << std::endl;
            Sleep(300);
            return NULL;
        }
        else
        {
            unit::unitcount += tank::useUnitCount;
            std::cout << "Unit Count : " << unit::unitcount << std::endl;
            Sleep(300);
            for(int i = 0; i < unit::maxUnitCount; i++)
            {
                if(unit::pUnit[i] == NULL)
                {
                    unit::pUnit[i] = new tank;
                    return unit::pUnit[i];
                }
            }
        }
        return NULL;    
    }
protected:
    tank(){}
    tank(const tank& rhs){}
};
 
class battlecruiser : public unit
{
public:
    int getUseCount() const
    {
        return battlecruiser::useUnitCount;
    }
    static const int useUnitCount = 8;
    static unit* CreateInstance(){
        if(battlecruiser::useUnitCount + unit::unitcount > unit::maxUnitCount)
        {
            std::cout << "Want : " << battlecruiser::useUnitCount << " Now : " << unit::unitcount << std::endl;
            Sleep(300);
            return NULL;
        }
        else
        {
            unit::unitcount += battlecruiser::useUnitCount;
            std::cout << "Unit Count : " << unit::unitcount << std::endl;
            Sleep(300);
            for(int i = 0; i < unit::maxUnitCount; i++)
            {
                if(unit::pUnit[i] == NULL)
                {
                    unit::pUnit[i] = new battlecruiser;
                    return unit::pUnit[i];
                }
            }
        }
        return NULL;        
    }
protected:
    battlecruiser(){}
    battlecruiser(const battlecruiser& rhs){}
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    const int testloop = 210;
 
    unit::init();
    int i;
    std::cout << "Create Marine" << std::endl;
    for(i = 0; i < testloop; i++)
    {
        marine::CreateInstance();
    }
    unit::DestroyAllUnit();
 
    std::cout << "Create tank" << std::endl;
    for(i = 0; i < testloop; i++)
    {
        tank::CreateInstance();
    }
    unit::DestroyAllUnit();
 
    std::cout << "Create battlecruiser" << std::endl;
    for(i = 0; i < testloop; i++)
    {
        battlecruiser::CreateInstance();
    }
    unit::DestroyAllUnit();
 
    return 0;
}

참조 : http://devsw.tistory.com



댓글 없음:

댓글 쓰기