본문 바로가기
카테고리 없음

싱글톤 패턴

by ByteBridge 2013. 3. 19.
반응형

/*

수비와 공격을 수행하는 유닛들로 구성된 게임에서~

각각의 유닛들은 객체 형태로만 생성되고,나름의 동작을 수행하다가, 상대편의 공격등에 의해 사살 또는 파괴되는 과정을 밟는다.

사살 또는 파괴되는 유닛에 해당하는 객체는 당연히 소멸될것임

 이러한 게임을 개발하는데 있어서 게임 개발자는 생성가능한 유닛의 최대 개수를 제한할 필요성을 가짐

 why ? 게임에 등장하는 유닛이 많아지면 컴퓨터 자원을 과도하게 사용할뿐아니라, 게임 전체의 속도를 느리게할수도잇음 또한 게임에 대한 흥미도도 떨어짐


 이러한 객체를 생성하더라도 최대 N까지만 객체가 생성되게 할필요가 있는경우 객체 생성을 제한 하기위하여 싱글톤 패턴이 사용됨


 클래스 자체적으로N개의 객체만 생성되게 제한하려면 ?

 먼저 객체가 임의로 생성될수 있는 경로를 없애야함

 즉 클래스 마다 객체 생성자를 외부로 공개하지않도록 함

 대신 객체가 제한적으로 생성되도록 별도의 멤버 함수를 두고 이를 통해서만 객체를 생성해줄 필요가있음


 한편으로는 생성된 객체들을 전체적으로 관리 되어야한다.

 why? 생성된 객체들이 관리되고 있어야 또 다른 객체 생성 요청이 잇을경우, 최대 N 개의 제한을 넘어서는 지를 판단할수있다.

 따라서 생성된 객체를 관리하기 위한 별도의 자료구조가 필요함

 개별 객체의 데이터 멤버로 존재해서는 안될것이다.

 왜냐? 개별 객체의 데이터 멤버는 해당 객체가 생성되어 소멸되기 전까지만 유효하므로 전체적인 객체의 생성, 소멸을 관리하기에는 부적함하기때문이다.

 따라서 생성된 객체를 관리하기 위한 자료구조는 클래스 차원에서 클래스 변수 형태로 정의 되어야함


*/

#include <iostream>

using namespace std;


#define N_UNIT    100


class GameUnit {

  public :

    static void InitUnitArray() {

       for (int i=0; i < N_UNIT; i++)

         pUnitArray_[i] = 0;

    }


    static GameUnit* CreateInstance() { return 0; }


    static void DestroyUnit(GameUnit* pUnit) {

      for (int i=0; i < N_UNIT; i++) {

        if (pUnitArray_[i] == pUnit) {

          delete pUnitArray_[i];

          pUnitArray_[i] = 0;

          return;

        }

      }

    }


    virtual void Display(int x, int y) = 0;

    virtual void DoAction() = 0;

  protected :

    GameUnit() {}

    GameUnit(const GameUnit& rhs) {}

    static GameUnit* pUnitArray_[N_UNIT];

};


// -- 클래스 변수 정의

GameUnit* GameUnit::pUnitArray_[N_UNIT];


class AttackUnit : public GameUnit {

  public : 

    static GameUnit* CreateInstance() { 

      for (int i=0; i < N_UNIT; i++) {

        if (pUnitArray_[i] == 0) {

          pUnitArray_[i] = new AttackUnit;

          return pUnitArray_[i];

        }

      }


      return 0;

    }


    void Display(int x, int y) {}

    void DoAction() {}

  protected :

    AttackUnit() {}

    AttackUnit(const AttackUnit& rhs) {}

};


class ProtectUnit : public GameUnit {

  public : 

    static GameUnit* CreateInstance() { 

      for (int i=0; i < N_UNIT; i++) {

        if (pUnitArray_[i] == 0) {

          pUnitArray_[i] = new ProtectUnit;

          return pUnitArray_[i];

        }

      }


      return 0;

    }


    void Display(int x, int y) {}

    void DoAction() {}

  protected :

    ProtectUnit() {}

    ProtectUnit(const ProtectUnit& rhs) {}

};


void 

main()

{

  GameUnit::InitUnitArray();


  GameUnit *pUnit1 = AttackUnit::CreateInstance();

  if (pUnit1 == 0)

    cout << "No More Create Unit" << endl;


  GameUnit *pUnit2 = ProtectUnit::CreateInstance();

  if (pUnit2 == 0)

    cout << "No More Create Unit" << endl;


  GameUnit::DestroyUnit(pUnit1);

  GameUnit::DestroyUnit(pUnit2);

}

/*

객체를 생성할때 생성자를 호출 하는것이 아니라 생성하고 싶은 객체의 종류에 해당하는 클래스의 CreateInstance() 멤버함수를 호출 하는 형태이다.

각 클래스의 생성자가 모두 protected 영역에 숨겨져 있어 직접적으로 호출 할수없기때문이다.

각 클래스의 createInstance 멤버 함수는 클래스 변수인 pUnitArray_ 배열 변수를 참조해서 빈공간이 있을 경우에만 객체를 생성시켜주기 때문에

공격 유닛이든 방어 유닛이든 전체적으로 최대 N개의 유닛 이하로 객체가 생성되게 보장함


클래스 자체에서 N개 이상의 객체 생성을 방지 해주기때문에  일일이 생성된 객체의 최대 개수가 N개 이하인지를 신경 쓸필요가 없다

*/

반응형