2011-10-12 3 views
1

소개 게임 프로그래밍 수업이 끝나고 있으며, 이전에 배운 OOP 경험과 함께 배운 기술을 결합하여 2D 게임을 만들기위한 작은 라이브러리를 만들고 싶습니다. 내 현재 관심사는 내 수업의 사례 모음을 관리하는 가장 좋은 방법입니다.오브젝트 관리 - 컨테이너 또는 공장?

사용중인 라이브러리 (DarkGDK)는 완전히 정수로 작동하는 자유 함수로 구성됩니다. dbSprite()와 같은 함수를 사용하여 "객체"를 만들면이를 참조하는 고유 한 ID (int 값)를 제공합니다. 정렬 유형은 "주소"입니다. 필자는 개인적으로이 접근법이 유용하다는 것을 알기 때문에 Image, Sprite 및 AnimatedSprite와 같은 자유 함수의 각 집합을 캡슐화하기위한 클래스를 만들었습니다 (두 Sprite 유형은 DarkGDK 라이브러리와 다릅니다.)

문제는 in 이러한 객체가 작동하도록하려면 적절한 주소에 대해 DarkGDK 함수를 호출하기 위해 여전히 고유 ID를 생성자에 전달해야합니다. 저는 ID로 모든 것을 함께 언급하는 것으로부터 벗어나려고 노력하고 있습니다.하지만 객체를 어떻게 만들어야하는지에 관해 논쟁 중입니다. 지금은 생성 된 각 객체에 대한 참조를 보유하고있는 일부 AssetManager 클래스가 있으며 기존 ID를 확인하고 고유 한 ID 만 허용하지만 관리 클래스 외부의 ID를 생성해야하는 문제는 여전히 해결되지 않습니다. 이것은 내가 공장이 최선의 접근 방법이 될 것이라고 생각하게했다.

나는 C#에서 인스턴스를 생성하기 위해 각 자산에 대한 적절한 생성자를 쉽게 호출 할 수있는 AssetFactory<T> where T:Asset을 만들 수 있음을 알고 있지만 C++에는 이러한 기능이 없습니다.

그래서 내가 취해야하는 접근법은 일종의 추상 AssetFactory를 사용하는 것이라고 생각합니다. 아이디어 (올바른지 여부)는 AssetFactory의 하위 항목이 사용중인 ID를 추적하고 적절한 개체 ID 만 발급한다는 것입니다. 이런 식으로 뭔가가 :

class Asset { 
    int m_index; 
    Asset(int index); 
}; 
class Image : public Asset { 
    Image(char* imgPath); 
    void Draw(); 
}; 
class Sprite : public Asset { 
    Sprite(Image* img); 
    void Draw(); 
}; 

class AssetFactory { 
private: 
    std::vector<Asset*> m_assets; 
    int GetUniqueID(); 
public: 
    AssetFactory(); 
    ~AssetFactory(); 

    virtual Asset* CreateAsset(); // but each class has different constructor parameters... 
}; 

class ImageFactory : public AssetFactory { 
    Asset* CreateAsset(char* imgPath); // ...so this wouldn't work (nor compile) 
}; 
class SpriteFactory : public AssetFactory { 
    Asset* CreateAsset(); // ...so will i be forced to call the default constructor and modify it later? 
}; 

여기서 문제는 위에서 언급 한 바와 같이, 다른 개체가이 디자인 논쟁을, 다른 생성자를 가지고 있다는 것입니다. 다른 접근 방법을 택해야합니까? 아니면 Factory Pattern에 대한 잘못된 생각을 갖고 있습니까?

편집 : 그것은 은 스프라이트에 대한 admissable이고 이미지가 동일한 ID를 가지고 있기 때문에 설명을 위해, 나는 스프라이트와 이미지에 대해 별도의 공장을 원하는 이유는. ID는 동일한 '유형'의 다른 저작물 중에서 유일해야합니다.

+0

나는 왜 이것이 downvoted인지 모르겠다. 그러나 나는 0으로 다시 투표 할 것이다. –

+1

FYI : 정수 메소드는 일반적으로 포인터로 데이터 구조와 인터페이스하지 않고 핸들 (정수)을 사용하기 때문에 일반적으로 핸들이라고합니다. – Daemin

+0

@Daemin : 그것이 제가 찾고 있던 용어입니다. 고맙습니다. C에서 일반적인 관행입니까? 비록 라이브러리가 MVC2008과 함께 출시되었지만, C++ 라이브러리처럼 투영되었습니다. 아키텍처와 동작이 나에게 C와 비슷한 것처럼 보입니다. –

답변

0

C#에 제네릭이있는 C++에는 템플릿이 있습니다. C++에서 제네릭 매개 변수에 대한 제약 조건을 쉽게 제공 할 수는 없지만 자산 유형에서 파생 된 유형 만 템플릿 매개 변수로 제공하도록하는 방법이 있습니다.

적절한 매개 변수를 생성자에 전달하려면 가변적 템플릿 메서드를 사용할 수 있습니다. 나는 현재 컴파일러를 가지고 있지 않다. 나중에 예제를 가지고 다시 편집 하겠지만, stackoverflow에서 많은 다른 가변적 인 템플릿 코드를 찾을 수있다.

+0

나에게 사용할 수있는 템플릿 기능을 알고 있지만, 생성 된 개체가 자산 유형이 아니라는 것을 보장하는 것이 아니라 관련된 개체 생성자를 관련 매개 변수와 함께 호출하는 방법입니다. –

+0

@wtfsven : 가변적 인 템플릿에 대한 내 대답을 편집했습니다. –

+0

C++ 03은 가변 템플릿을 지원하지 않으므로 거기서 운이 좋지 않습니다. –

0

어쩌면 내가 놓친 것이 있습니다. 왜 당신이 왜 ID 생성기를 AssetManager 내부로 옮길 수 없었는지 분명하지 않았습니다.이 방법은 외부 세계의 고유 ID에 대한 모든 비참함을 숨기고 있습니다.

어쨌든 ID를 추적해야하는 경우 관리자 클래스가 필요하며 여기까지는 내 게시물에서 알 수 있습니다. 팩토리 클래스 대신 factory 메소드를 사용하면 방금 finishline에 도착했습니다. 남아있는 유일한 문제는 ID를 처리하는 것이지만, Asset 클래스의 가상 소멸자에서 수행 할 수 있습니다.깨끗하게 유지하려면 관리자에서 보호 된 메소드를 제공하고 매니저의 자산 클래스 소멸자 (또는 일부 정리 기능) 친구를 만들어야합니다.

+0

나는이 접근법을 가능하게하기 위해 실제로 아키텍처를 변경했다. 이제 저는 Factory Pattern을 가지고 놀고 있습니다. :) 입력 주셔서 감사. –

1

라이브러리에서 임의의 ID를 허용하고 상대적으로 동일한 주소 공간 (예 : sizeof (int) == sizeof (int *))에서 작업하는 경우 문제를 해결하는 것이 매우 쉽습니다. 사실상 내가 아는 모든 32 비트 컴파일러. ID를 생성하는 것은 사소한 것입니다 - 포인터를 다시 해석하십시오.

class Sprite { 
    int GetUniqueID() { return reinterpret_cast<int>(this); } // easies 
public: 
    // public interface 
}; 

또한 실제로는 이전 ID를 다시 사용할 가치가 없습니다. 새로운 것을 계속 만들어라. 내 말은, 당신은 32 비트 정수로 공간을 다 써 버리지 않을 것입니다.

마지막으로 여기에서는 런타임 상속을 사용할 수 없습니다. 필요한 경우 컴파일 타임 믹스 인을 사용하십시오.

+0

그게 좋은 생각이야! 불행하게도 ID의 최대 값은 USHRT_MAX이므로 고유성을 위해 추가 조작을해야합니다. –

+0

reinterpret_cast를 드물게 사용하십시오. 당신이 그것을 사용할 때, 당신은 본질적으로 컴파일러에게 "어이 바보, 닥쳐. 나는 정확히 내가 뭘하는지 알아." –

관련 문제