更新:这个答案假设存在某种可以读取并传递给工厂的魔法,但显然情况并非如此。我将答案留在这里是因为 a) 我可能会更新它,并且 b) 无论如何我都喜欢它。
与您自己的答案没有太大不同,不使用 C++11 技术(我还没有机会更新它,或者让它返回一个智能指针等),也不完全是我自己的工作,但这是我使用的工厂类。重要的是(恕我直言)它不会调用每个可能的类的方法来找到匹配的方法——它是通过映射来完成的。
#include <map>
// extraneous code has been removed, such as empty constructors, ...
template <typename _Key, typename _Base, typename _Pred = std::less<_Key> >
class Factory {
public:
typedef _Base* (*CreatorFunction) (void);
typedef std::map<_Key, CreatorFunction, _Pred> _mapFactory;
// called statically by all classes that can be created
static _Key Register(_Key idKey, CreatorFunction classCreator) {
get_mapFactory()->insert(std::pair<_Key, CreatorFunction>(idKey, classCreator));
return idKey;
}
// Tries to create instance based on the key
static _Base* Create(_Key idKey) {
_mapFactory::iterator it = get_mapFactory()->find(idKey);
if (it != get_mapFactory()->end()) {
if (it->second) {
return it->second();
}
}
return 0;
}
protected:
static _mapFactory * get_mapFactory() {
static _mapFactory m_sMapFactory;
return &m_sMapFactory;
}
};
要使用它,您只需声明基本类型,并为每个类将其注册为静态。请注意,当您注册时,会返回密钥,因此我倾向于将其添加为类的成员,但这不是必需的,只是整洁:) ...
// shape.h
// extraneous code has been removed, such as empty constructors, ...
// we also don't technically need the id() method, but it could be handy
// if at a later point you wish to query the type.
class Shape {
public:
virtual std::string id() const = 0;
};
typedef Factory<std::string, Shape> TShapeFactory;
现在我们可以创建一个新的派生类,并将其注册为可创建的TShapeFactory
...
// cube.h
// extraneous code has been removed, such as empty constructors, ...
class Cube : public Shape {
protected:
static const std::string _id;
public:
static Shape* Create() {return new Cube;}
virtual std::string id() const {return _id;};
};
// cube.cpp
const std::string Cube::_id = TShapeFactory::Register("cube", Cube::Create);
然后我们可以创建一个新项目,在这种情况下,是一个字符串:
Shape* a_cube = TShapeFactory::Create("cube");
Shape* a_triangle = TShapeFactory::Create("triangle");
// a_triangle is a null pointer, as we've not registered a "triangle"
这种方法的优点是,如果您创建一个新的派生的、工厂可生成的类,则无需更改任何其他代码,只要您可以看到工厂类并从基类派生:
// sphere.h
// extraneous code has been removed, such as empty constructors, ...
class Sphere : public Shape {
protected:
static const std::string _id;
public:
static Shape* Create() {return new Sphere;}
virtual std::string id() const {return _id;};
};
// sphere.cpp
const std::string Sphere::_id = TShapeFactory::Register("sphere", Sphere::Create);
我将留给读者的可能改进包括添加诸如:typedef _Base base_class
to之类的内容Factory
,以便在您声明自定义工厂时,您可以使您的类派生自TShapeFactory::base_class
等等。工厂可能还应该检查一个密钥是否已经存在,但是再次......它作为一个练习留下。