728x90

개발을 하다 보면 공유를 고려하게 되는데 논리적인 관점과 구현 측면에서 자원을 효율적으로 사용하기 위한 공유 두 가지가 필요하게 됩니다. 논리적으로 공유하기 위해서는 데이터베이스나 파일에 데이터를 넣고 꺼내는 식으로 공유를 하게 되고 효율적으로 사용하기 위해서는 여러 목적을 위해 하나의 변수를 통해 공유를 합니다. 여기서 두 번째 경우의 자원 사용 효율화를 위한 공유 문제를 해결하기 위한 설계를 어떻게 하면 좋을까요

 

메탈 슬러그 같은 게임을 보면 모덴군이라는 적군이 등장합니다. 모덴군의 동작을 보면 결국 이미지의 연속 데이터로 이루어져 있습니다. 이 동작을 표현하기 위한 이미지는 각 모덴군 객체마다 별도로 저장하는 것이 일반적이지만 이럴 경우 적군이 등장하면서 메모리의 양이 증가하기 때문에 옛날 콘솔 같은 한정된 메모리를 사용하는 장치에서는 문제가 일어날 수 있습니다.

이미지를 객체 단위가 아닌 화면 차원에서 이미지를 저장하고 관리하는 것도 해결 방법이 될 수 있겠지만 캐릭터가 화면 안에서 벗어나거나 이럴 때 캐릭터의 일부만 보여만 보여주는 작업을 해야 하는데 이런 계산도 수행하는 것이 쉽지 않습니다.

 

다른 방법으로 이미지를 미리 저장하고 관리하고 있는 객체를 만들어주는 방법이 있습니다. 이 객체로부터 정보를 공유 받아 사용하는데 공유 가능한 정보와 그렇지 않은 정보를 분리하는 것이 필요합니다. 예를 들어 공유돼야 할 정보는 동작에 대한 이미지 정보들 하지만 표시해야 하는 위치 정보는 공유할 필요가 없습니다. 이렇게 공유하지 않을 정보들은 개별 객체(각 모덴군)에 저장하고 그리고 공유할 정보는 별개의 객체를 정의해 저장하여 관리하게 합니다. 이럴 때 공유 정보를 담고 있는 객체를 Flyweight 객체라고 합니다. 그리고 공유할 정보들은 Flyweight 객체 내부에 저장하기 때문에 Intrinsic State라고 하고 공유 불가능한 정보는 Flyweight 외부에 저장하기 때문에 Extrinsic State라고 합니다.

 

각 모덴군들 객체는 MordenImage를 멤버로 가지고 있습니다. 모덴군 객체들은 Flyweight 객체들이 저장되어 있는 ImagePool에서 이미지 정보들을 공유받고 있습니다.

class MordenImage {
    virtual void Draw(int x, int y) = 0; 
protected:
    List<Image*> mordenImage;		// 각 모션에 대한 이미지 정보를 기록할 변수
};

class MoveImage : public MordenImage {
    static MordenImage* CreateInstance() {
        if ( pInstance == 0 ) {
        	pInstance = new MoveImage;
        }
        return pInstance;
    }
    void Draw(int x, int y) { cout << "Draw in x,y position"; }
protected:
    MoveImage() { cout << "Load Image"; }
    static MordenImage* pInstance;
};
MordenImage* MoveImage::pInstance = 0;

class KnifeAttack : public MordenImage {
    static MordenImage* CreateInstance() {
        if ( pInstance == 0 ) {
        	pInstance = new KnifeAttack;
        }
        return pInstance;
    }
    void Draw(int x, int y) { cout << "Draw in x,y position"; }
protected:
    KnifeAttack() { cout << "Load Image"; }
    static MordenImage* pInstance;
};
MordenImage* KnifeAttack::pInstance = 0;

class MordenEnemy {
    MordenEnemy(int x, int y) {
        curX = x; curY = y;
        pCurImage = MoveImage::CreateInstance();
    }
    void Attack() {
        pCurImage = KnifeAttack::CreateInstance();
        Draw();
    }
    void Draw() { pCurImage->Draw(curX, curY); }
private:
    int curX, curY;
    MordenImage* pCurImage;
};

int main()
{
    MordenEnemy e1(10,10);
    e1.Attack();
}

소스를 보면 각 이미지 종류별로 객체를 가지고 있어 생성될 때 이미지 정보를 로드합니다. 그리고 모덴군 객체에서 Attack이나 특정 행동을 할 때 각 액션에 맞는 객체를 가져옵니다. 싱글톤 패턴을 이용해서 객체는 한 개만 생성이 되도록 짜여 있습니다. 이미지를 담당하는 객체에서 가져온 객체를 통해 Draw를 해주게 됩니다.

 

 

728x90

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

C++ 책임 연쇄 패턴  (0) 2021.05.30
C++ 프록시 패턴  (0) 2021.05.29
C++ 퍼사드 패턴  (0) 2021.05.16
C++ 데코레이터 패턴  (0) 2021.05.16
C++ 컴포지트 패턴  (0) 2021.05.15

+ Recent posts