Singleton 패턴

Singleton 패턴


정의


  •  객체가 생성되는 개수를 제한하는 형태



상황

  • 던전앤파이터는 MORPG로 한 던전에 최대 4명의 유저가 입장할 수 있다. 이때, 캐릭터는 반드시 플레이어 수만큼만 생성되어야한다. 


    (적당한 이미지를 찾기가 힘들다..남들의 플레이컷을 가져오자니 뭔가 찔리고..그냥 안올리는걸로; 다음에 출타나가면 피방가서 적당한걸로 찍어올리자)


가장 쉽게 생각할 수 있는 방법은 전역변수로 객체의 개수를 관리하는 방법이다.


 #include<iostream>


#define MAX_PLAYER 4


class GameUnit

{

public:

void Display() { std::cout << "플레이어" << std::endl; }

};


GameUnit* pUnitArr[MAX_PLAYER];


class Dungeon

{

public:

GameUnit* EnterDungeon()

{

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

{

if(pUnitArr[i] == NULL)

{

pUnitArr[i] = new GameUnit();

return pUnitArr[i];

}

}

return NULL;

}


void PlayDungeon()

{

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

{

if(pUnitArr[i] != NULL)

{

pUnitArr[i]->Display();

}

}

}


void ExitDungeon()

{

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

{

if(pUnitArr[i] == NULL)

continue;

else

{

delete pUnitArr[i];

pUnitArr[i] = NULL;

}

}

}

};


int main()

{

int playernum = 0;

Dungeon dungeon;


std::cin >> playernum;


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

dungeon.EnterDungeon();

dungeon.PlayDungeon();

dungeon.ExitDungeon();


return 0;


}




적어도 내가 보기엔 얼추 괜찮아보인다.

Dungeon가 객체 생성 요청에대해 전역배열 변수 pUnitArr에 NULL이 있을 때에만 객체를 생성해주고 있다. 또한 pUnitArr 배열은 매크로 MAX_PLAYER만큼만의 공간을 가지고 있다. 

이러면 플레이어 개수를 제한하면서 요청하는 개수만큼만의 객체를 만들 수 있다.


그러나 이러한 방식은 코드가 길어질 때에 제한을 일일히 신경써서 작성해야한다는 불편함을 부른다. 예를들어 GameUnit의 하위 객체를 만들거나, 코드중간에 객체를 생성할 코드를 삽일할 가능성은 얼마든지 존재한다.


이런 불편함을 해결하기위해 Singleton 패턴이 필요하다.


Singleton 패턴의 기본은 객체의 개수를 제한하는 것이지만, 이를 위해서는 객체가 임의로 생성될 수 있는 경로를 없애버려야한다. 경로를 없애버리지 않는다면 똑같은 문제를 부를 뿐이다.

이를 위해서는 각 클래스마다 객체 생성자를 외부(public)로 공개해서는 안된다. 대신 Dungeon 클래스의 EnterDungeon() 함수처럼 객체가 제한적으로 생성되도록 별도의 멤버함수를 두고 이를 통해서만 객체를 생성하면 된다.


객체의 생성자를 없애면서 객체를 생성하는 함수를 밖으로 두기위해서는 전역배열 변수를 객체 내부로 불러와야한다.


그러면 다음과 같은 형태가 되어야한다.



#include <iostream>

#include <vector>


#define MAX_PLAYER 4


class GameUnit

{

public:

static void Init()

{

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

{

pUnitArr[i] = NULL;

}

}


static void Destory()

{

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

{

if(pUnitArr[i] == NULL) continue;

else 

{

delete pUnitArr[i]; 

pUnitArr[i] = NULL; 

}

}

}


static void Destory(GameUnit* pUnit)

{

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

{

if(pUnitArr[i] == pUnit)

{

delete pUnitArr[i] ;

pUnitArr[i] = NULL;

}

}

}


static GameUnit* CreateInstance()

{

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

{

if(pUnitArr[i] == NULL)

{

pUnitArr[i] = new GameUnit();

return pUnitArr[i];

}

}

return NULL;

}


public:

void Display() { std::cout << "플레이어!" << std::endl; }


protected:

GameUnit() {}

GameUnit(const GameUnit& rhs) {}

static GameUnit* pUnitArr[MAX_PLAYER];

};


GameUnit* GameUnit::pUnitArr[MAX_PLAYER];


class Dungeon

{

public:

static Dungeon* GetInstance()

{

if(pDungeon == NULL)

pDungeon = new Dungeon();


return pDungeon;

}


void Init()

{

}


void Destory()

{

if(pDungeon != NULL)

{

delete pDungeon;

pDungeon = NULL;

}

}


void EnterDungeon(int playernum)

{

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

{

GameUnit* pGameUnit = GameUnit::CreateInstance();

this->vecGameUnit.push_back(pGameUnit);

}

}


void PlayDungeon()

{

int length = vecGameUnit.size();


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

{

vecGameUnit[i]->Display();

}

}


void ExitDungeon()

{

GameUnit::Destory();

}


protected:

Dungeon() {}

Dungeon(const Dungeon& rhs) {}


static Dungeon* pDungeon;

std::vector<GameUnit*> vecGameUnit;

};


Dungeon* Dungeon::pDungeon = NULL;


int main()

{

GameUnit::Init();

Dungeon::GetInstance()->Init();


int playernum = 0;


std::cin >> playernum;


Dungeon::GetInstance()->EnterDungeon(playernum);

Dungeon::GetInstance()->PlayDungeon();

Dungeon::GetInstance()->ExitDungeon();


Dungeon::GetInstance()->Destory();

GameUnit::Destory();


return 0;

}


하다보니까 싱글톤 패턴을 만드는 두가지 방법이 나왔다. 솔직히 뭘 모르고 쓰던 때에는 Dungeon 형태를 자주 즐겨써서 이걸로 쓰면 되겠지했는데 GameUnit에는 적용이 안되겠더라. 

스타일의 차이인 것같아서 두 가지 다 써보았다. 거기서 거기랄까.


여튼간에 이렇게 코드를 사용함으로서 객체의 생성자를 없애면서 객체를 생성하는 함수를 밖으로 두었다. 

객체의 생성자는 protected나 private으로 감추면되고, 외부에서 객체를 접근할 때는 전역 객체로 접근하면 된다.



------------------------------------------------------------------------------------------------------------------------------------------------------------------

이번주는 훈련과 행사가 많아서 좀 정신이 없었다.

그나마 자주 쓰던거라 그나마 좀 빨리 쓴 것같네..

'프로그래밍 > 프로그래밍 관련' 카테고리의 다른 글

VS를 깃허브에 연동  (0) 2018.01.22
Command 패턴 (1)  (0) 2018.01.17
ProtoType 패턴  (0) 2016.10.15
Abstract Factory 패턴  (0) 2016.10.15
Cookie, Session 그대의 의미는..  (0) 2015.10.29
더보기

댓글,

Lowpoly

게임 서버 프로그래머 지망생