对象管理 - 容器还是工厂?

时间:2011-10-12 10:43:06

标签: c++ oop factory-pattern

我即将结束入门游戏编程课程,并希望将我在课堂上学到的技能与之前的OOP经验相结合,创建一个用于制作2D游戏的小型库。但是,我目前关注的是管理我的类实例集合的最佳方法。

我正在使用的库(DarkGDK)完全由作用于整数的自由函数组成。当使用诸如dbSprite()之类的函数创建“对象”时,你给它一个唯一的ID(int值)来引用它 - 我猜的是“地址”。我个人觉得这种方法很糟糕,所以我创建了一些类来封装每一组免费函数,比如Image,Sprite和AnimatedSprite(两种精灵类型在DarkGDK库中是不同的。)

问题是,为了使这些对象起作用,我仍然必须将唯一的ID传递给构造函数,以便针对适当的地址调用DarkGDK函数。我试图通过ID一起转移引用这些东西,但我正在讨论如何创建对象。目前我有一些AssetManager类保存对创建的每个对象的引用,检查现有ID并仅允许唯一ID,但这仍然无法解决被迫生成管理类外部ID的问题。这让我觉得工厂是最好的方法。

我知道在C#中我可以创建一个AssetFactory<T> where T:Asset,可以轻松地为每个Asset调用适当的构造函数来创建实例,但据我所知,C ++没有这样的设施。

所以我认为我应该采用的方法是使用某种抽象的AssetFactory。 我的想法(正确与否)是AssetFactory的子项将跟踪正在使用的ID,并仅发出approriate对象的唯一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?
};

这里的问题是,如上所述,不同的对象具有不同的构造函数,使得这种设计没有实际意义。我应该采取不同的方法吗?或者我对工厂模式有错误的想法?

编辑:为了澄清,我想要Sprites和Images的单独工厂的原因是因为 允许Sprite和图像具有相同的ID。 ID必须在同一“类型”的其他资产中唯一。

3 个答案:

答案 0 :(得分:1)

如果您的库允许任意ID并且您在相对相等的地址空间(例如sizeof(int)== sizeof(int *))中工作,这是一个非常微不足道的问题,这几乎都是正确的我知道的32位编译器。然后生成ID是微不足道的 - 只需重新解释指针。

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

此外,重新使用旧ID实际上可能不值得。继续制作新的。我的意思是,你不会用32位整数耗尽空间。

最后,你绝对不能在这里使用运行时继承。如果必须,请使用编译时mixin。

答案 1 :(得分:0)

在C#具有泛型的地方,C ++有模板。你不能轻易地在C ++中提供泛型参数的约束,但是有一些方法可以确保你只提供一个派生资产类型作为模板参数。

为了将适当的参数传递给构造函数,可以使用可变参数模板方法。我目前没有可用的编译器......稍后我将使用一个示例再次编辑,尽管您可以在stackoverflow上找到大量其他可变参数模板代码。

答案 2 :(得分:0)

也许我错过了什么,我不清楚你为何无法在AssetManager中移动ID生成器,这样就可以隐藏外部世界中唯一ID的所有痛苦。

无论如何,如果您需要跟踪ID,那么就我在此时的帖子中所知,您需要经理类。如果您使用工厂方法而不是工厂类,那么您刚刚到达终点线:)剩下的唯一问题是处理ID,但您可以在Asset类的虚拟析构函数中执行。如果你想保持它干净,那么你应该在管理器中为它提供一个受保护的方法,并使经理的资产类析构函数(或一些清理函数)成为朋友。