开发者

Object Managment - Container or Factory?

I'm nearing the end of a introductory game programming class, and would like to combine the skills I learned in class with my previous OOP experience to create a small library for making 2D games. My current concern, though, it the best way to manage collections of instances of my classes.

The library I'm using (DarkGDK) is made up entirely of free functions that act on integers. When an "object" is created with a function such as dbSprite(), you give it a unique ID (int value) to refer to it with--an "address" of sorts, I guess. I personally find this approach apalling, so I've created classes to encapsulate each set of free functions such as Image, Sprite, and AnimatedSprite (the two sprite types are different in the DarkGDK library.)

The trouble is, in order for these objects to work, I still have to pass a unique ID to the constructor in order to call the DarkGDK functions against the appropriate address. I'm trying to move away from refering to these things by ID all together, but I'm debating on how the objects should be created. At the moment I have some AssetManager classes that holds references to each object created, check for existing IDs and only allow unique ones, but this still does not solve the problem of being forced to generate an ID external to the man开发者_C百科agement class. This led me to think a Factory would be the best approach.

I know in C# I could create an AssetFactory<T> where T:Asset that can easily call the appropriate constructors for each Asset to create the instances, but to my knowledge C++ has no such facilites.

So I think the approach I should take is using some sort of abstract AssetFactory. My idea (correct or not) is that children of the AssetFactory would keep track of the IDs in use and only issue approriate objects unique IDs. Something like this:

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?
};

The problem here is that, as noted above, the different objects have different constructors, making this design moot. Should I be taking a different approach? Or do I just have the wrong idea of the Factory Pattern?

EDIT: For clarification, the reason I want separate factories for Sprites and Images is because it is admissable for a Sprite and an image to have the same ID. The IDs must only be unique among other assets of the same "type."


This is a pretty trivial problem to solve, if your library allows arbitrary IDs and you're working in a relatively equal address space (e.g. sizeof(int) == sizeof(int*)), which is true on virtually all 32bit compilers that I know of. Generating the IDs is then trivial- just reinterpret_cast the pointer.

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

In addition, it's actually probably not worth it to re-use old IDs. Just keep making new ones. I mean, you're not gonna run out of space in a 32bit integer.

Finally, you definitely cannot use run-time inheritance here. Use a compile-time mixin, if you must.


Where C# has generics, C++ has templates. You can't so easily provide the constraints on the generic parameter in C++, but there are ways to make sure that you only give a derived-from-Asset type as the template parameter.

In order to pass the appropriate parameters to the constructor, you can use a variadic template method. I don't have a compiler available to me at the moment... I'll edit again later with an example, although you can find plenty of other variadic template code on stackoverflow.


Maybe I missed something, it wasn't clear for me you why couldn't move the ID generator inside the AssetManager, this way hiding all the misery of the unique IDs from the outside world.

Anyway, if you need to keep track of the IDs you will need the manager class as far as I can tell at this point from your post. If you use factory methods instead of factory classes you have just arrived to the finish line :) The only problem which remains is the disposal of the IDs, but you can do in the virtual destructor of the Asset class. If you want to keep it clean, then you should provide a protected method for it in the manager, and make the Asset classes destructor (or some Cleanup function) friend of the manager.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜