728x90

스타크래프트 게임을 보면 인구수가 200이 제한이 되어 있습니다. 이처럼 객체를 생성하는 데 있어 제한을 두면서 생성해야 할 경우도 있습니다.

간단하게 생각했을 때는 유닛을 전역으로 관리하는 방법이 있습니다.

#define MAX_UNIT 200

eunm UnitType {
	MARINE = 1,
	FIREBAT = 2,
	SIEGETANK 3
};

class Unit { virtual void Attack() = 0; };
class Marine : public Unit { void Attack() { cout << "Marine Attack"; } };
class Firebat : public Unit { void Attack() { cout << "Firebat Attack"; } };
class SiegeTank : public Unit { void Attack() { cout << "SiegeTank Attack"; } };

Unit* pUnitArray[MAX_UNIT];

void InitUnitArray() {
	for(int i = 0; i < MAX_UNIT ; i++) { pUnitArray[i] = 0; }
}
Unit* CreateUnit(UnitType type) {
    for(int i = 0 ; i < MAX_UNIT; i++) {
        if (pUnitArray[i] == 0) {
    	switch(type) {
        case MARINE:
        	pUnitArray[i] = new Marine;
            break;
        case Firebat:
        	pUnitArray[i] = new Firebat;
            break;
        case Firebat:
        	pUnitArray[i] = new SiegeTank;
            break;       
        }
        return pUnitArray[i];
	}
    return 0;
}

int main()
{
	InitUnitArray();
    Unit* pUnit = CreateUnit(MARINE);
    if ( pUnit == 0 ) { cout << "Failed to create unit"; }
}

위와 같이 전역 Unit 배열로 관리해서 배열에 빈 공간에 넣고 다 채워져있다면 생성을 막는 방식으로 생성할 수 있습니다. 이렇게 되면 관리는 되지만 사용자가 임의로 CreateUnit 함수 없이 생성한다면 그 수를 제한할 수 없습니다. 사용자가 임의로 객체를 생성할 수 없게 생성자를 외부로 공개하지 않고 생성할 수 있는 멤버 함수를 제공하여 그 함수로만 생성을 할 수 있게 해야 합니다. 그리고 전역으로 관리되던 Unit 배열은 상위 클래스에 static으로 가지고 있어야 합니다.

#define MAX_UNIT 200

class Unit { 
	virtual void Attack() = 0; 
    static void InitUnitArray() {
		for(int i = 0; i < MAX_UNIT ; i++) { pUnitArray[i] = 0; }
	}
	static Unit* CreateInstance() { return 0; }
    static void DestoryUnit(Unit* pUnit) {
    	for(int i = 0 ; i < MAX_UNIT; i++) {
	        if (pUnitArray[i] == pUnit)  { 
            	delete pUnitArray[i];
                pUnitArray[i] = 0;
                return ;
            }
        }
    }
protected:
	Unit();
    static Unit* pUnitArray[MAX_UNIT];
};

Unit* Unit::pUnitArray[MAX_UNIT];

class Marine : public Unit { 
	void Attack() { cout << "Marine Attack"; } 
    static Unit* CreateInstance() {
    	for(int i = 0 ; i < MAX_UNIT; i++) {
	        if (pUnitArray[i] == 0)  { 
            	pUnitArray[i] = new Marine; 
                return pUnitArray[i];
            }
        }
		return 0;
	}
protected:
	Marine();
};
    
class Firebat : public Unit { 
	void Attack() { cout << "Firebat Attack"; } 
    static Unit* CreateInstance() {
    	for(int i = 0 ; i < MAX_UNIT; i++) {
	        if (pUnitArray[i] == 0)  { 
            	pUnitArray[i] = new Firebat; 
                return pUnitArray[i];
            }
        }
		return 0;
	}
protected:
	Firebat();
};


int main()
{
    Unit::InitUnitArray();
    
    Unit* pMarineUnit = Marine::CreateInstance();
    if ( pMarineUnit == 0 ) { cout << "Failed to create unit"; }
    Unit* pFirebatUnit = Firebat::CreateInstance();
    if ( pFirebatUnit == 0 ) { cout << "Failed to create unit"; }
    
    Unit::DestoryUnit(pMarineUnit);
    Unit::DestoryUnit(pFirebatUnit);
}

이렇게 된다면 CreateInstance를 통해서만 객체가 생성이 가능하고 빈 공간이 있을때만 생성이 가능하므로 설계대로 최대 개수만큼 제한이 가능합니다. 

 

이처럼 Singletone 패턴을 통해 객체를 관리하기 위해서는 생성자, 복사 생성자를 protected로 설정해서 임의로 생성을 못하게 막아야 하고 객체를 관리하기 위한 배열 혹은 자료구조는 최상위 클래스에 대한 자료형이어야 합니다. 마지막으로 CreateInstance를 통해 생성된 객체는 임의로 delete 하게 되면 관리가 제대로 안되기 때문에 DestoryUnit 같은 관리 함수를 통해 삭제가 되도록 해야 합니다.

728x90

'Programming > C++' 카테고리의 다른 글

C++ 브릿지 패턴  (0) 2021.05.15
C++ 어댑터 패턴  (0) 2021.05.09
C++ 프로토 타입 패턴  (0) 2021.05.08
C++ 팩토리 메소드 패턴  (0) 2021.05.08
C++ 빌더 패턴  (0) 2021.05.02

+ Recent posts