我们可以抽象出Factory细节,依赖客户端提供枚举到类类型的映射:
template<typename ENUM, typename T>
struct Factory
{
typedef std::map<ENUM, T*(*)()> map_type;
static map_type factoryMapping_;
static T* Create(ENUM c)
{
return factoryMapping_[c]();
}
static void Init(map_type _mapping)
{
factoryMapping_ = _mapping;
}
};
template<typename ENUM, typename T>
typename Factory<ENUM, T>::map_type Factory<ENUM,T>::factoryMapping_;
现在,客户的工作是为我们提供在给定枚举值的情况下创建Base* 的方法。
如果您愿意并且能够使用模板抽象派生类的创建,那么您可以节省相当多的打字时间。
我的意思是,让我们创建一个模板函数来创建一个派生类(无需任何真正的正确性检查):
template<typename Base, typename Derived>
Base* CreateDerived()
{
return new Derived();
}
现在我可以定义一个枚举和相关的类层次结构:
enum ClassType {A, B};
struct Foo
{
virtual void PrintName() const
{
std::cout << "Foo\n";
}
};
typedef Factory<ClassType, Foo> FooFactory ;
struct DerivedOne : public Foo
{
virtual void PrintName() const
{
std::cout << "DerivedOne\n";
}
};
struct DerivedTwo : public Foo
{
virtual void PrintName() const
{
std::cout << "DerivedTwo\n";
}
};
然后像这样使用它:
// set up factory
std::map<ClassType, Foo*(*)()> mapping;
mapping[A] = &CreateDerived<Foo, DerivedOne>;
mapping[B] = &CreateDerived<Foo, DerivedTwo>;
FooFactory::Init(mapping);
// Use the factory
Foo* f = FooFactory::Create(A);
f->PrintName();
当然,这稍微简化了您的问题,即将工厂细节从基类中移出并暂时忽略了子类本身是模板化的。根据您的域中为每种类型创建良好的 CreateDerived 函数的难度,您最终可能不会节省大量的输入。
编辑:我们可以利用std::map::find 修改我们的Create 函数以返回NULL。为简洁起见,我省略了它。如果您关心性能,那么是的,O(log n) 搜索渐进地比简单的切换慢,但我强烈怀疑这最终会成为热门路径。