如何在不使用switch的情况下随机选择要实例化的类?

时间:2011-10-18 06:38:59

标签: c++ class types

我正在使用纠结的条件网重构一个3000 + -line类,并切换到一组工作类。以前,构造函数的一部分将通过以下代码选择要使用的“类型”事物:

enum Type { FOO, BAR, BAZ };

Type choices[] = { FOO, FOO, BAR, BAZ }; // weighted towards FOO
m_type = choices[rand()%4];

[...later...]

void Run() {
    switch (m_type) {
        case FOO: do_foo(); break;
        case BAR: do_bar(); break;
        case BAZ: do_baz(); break;
    }
}

重构后,我有单独的TypeFooTypeBarTypeBaz类,每个类都有自己的Run()方法来完成他们的工作。可悲的是,它的类选择代码很复杂。我不知道有什么方法可以保留一个可能的类列表来构建,所以我有这个:

Type *m_type;

switch (mrand()%4) {
    case 0: case 1: m_type = new TypeFoo(); break;
    case 1:         m_type = new TypeBar(); break;
    case 2:         m_type = new TypeBaz(); break;
}

这仍然值得改变,因为这个初始化代码不会定期调用,但现在更难修改此列表,更改权重等。

是否有相对简单的方法来实现原始代码的清晰度?

2 个答案:

答案 0 :(得分:14)

答案是:基类和函数指针数组可以帮助你做到这一点。

struct Base { virtual ~Base() {} }; //make ~Base() virtual
struct Foo : Base {};
struct Bar : Base {};
struct Baz : Base {};

template<typename T>
Base *Create() { return new T(); }

typedef Base* (*CreateFn)();

CreateFn create[] = 
         {
              &Create<Foo>, 
              &Create<Foo>,   // weighted towards FOO
              &Create<Bar>, 
              &Create<Baz>
         }; 
const size_t fncount = sizeof(create)/sizeof(*create);

Base *Create()
{
   return create[rand() % fncount](); //forward the call
}

然后将其用作(ideone demo):

int main() {
        Base *obj = Create();
        //work with obj using the common interface in Base

        delete obj; //ok, 
                    //the virtual ~Base() lets you do it 
                    //in a well-defined way
        return 0;
}   

答案 1 :(得分:2)

我建议创建一个公共基类(如果你还没有),然后使用a factory class来封装创建过程。工厂只会返回一个指向基类的指针,该基类具有原型运行方法。

这些方面的东西:

class Type
{
    virtual void Run() = 0;
};

class TypeFoo : public Type
{
public:
    TypeFoo() {};
    virtual void Run() {};
    static Type* Create() { return new TypeFoo(); };
};

class TypeBar : public Type
{
public:
    TypeBar() {};
    virtual void Run() {};
    static Type* Create() { return new TypeBar(); };
};

class TypeBaz : public Type
{
public:
    TypeBaz() {};
    virtual void Run() {};
    static Type* Create() { return new TypeBaz(); };
};

class TypeFactory
{
    typedef Type* (*CreateFn)();

public:
    static Type* RandomTypeFooWeighted()
    {
        CreateFn create[] = 
        {
            TypeFoo::Create, 
            TypeFoo::Create,   // weighted towards FOO
            TypeBar::Create, 
            TypeBaz::Create
        };   
        const int fncount = sizeof(create)/sizeof(*create);
        return create[ rand()%fncount ]();
    }
};

所以要使用它,你可以打电话:

Type *t = TypeFactory::RandomTypeFooWeighted();

归功于Nawaz的函数指针位和bobs。