我正在使用纠结的条件网重构一个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;
}
}
重构后,我有单独的TypeFoo
,TypeBar
和TypeBaz
类,每个类都有自己的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;
}
这仍然值得改变,因为这个初始化代码不会定期调用,但现在更难修改此列表,更改权重等。
是否有相对简单的方法来实现原始代码的清晰度?
答案 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。