[英]Instantiating classes by name with factory pattern
Suppose I have a list of classes A, B, C, ...
which all inherit from Base
. 假设我有一个A, B, C, ...
类的列表A, B, C, ...
它们都继承自Base
。
I get the class name as a string from the user, and I want to instantiate the right class and return a pointer to Base
. 我从类用户获取类名作为字符串,我想实例化正确的类并返回指向Base
的指针。 How would you implement this? 你会如何实现这个?
I thought of using a hash-table with the class name as the key, and a function pointer to a function that instantiates the right class and returns a Base *
. 我想过使用带有类名作为键的哈希表,以及一个函数指针,该函数指向实例化右类并返回Base *
的函数。
However, I think I might be able to use the factory pattern here and make it a lot easier, but I just can't quite remember it well, so I though I'd ask for suggestions. 但是,我想我可以在这里使用工厂模式并使其更容易,但我不能很好地记住它,所以我虽然我会寻求建议。
Here is a generic factory example implementation: 这是一个通用的工厂示例实现:
template<class Interface, class KeyT=std::string>
struct Factory {
typedef KeyT Key;
typedef std::auto_ptr<Interface> Type;
typedef Type (*Creator)();
bool define(Key const& key, Creator v) {
// Define key -> v relationship, return whether this is a new key.
return _registry.insert(typename Registry::value_type(key, v)).second;
}
Type create(Key const& key) {
typename Registry::const_iterator i = _registry.find(key);
if (i == _registry.end()) {
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
": key not registered");
}
else return i->second();
}
template<class Base, class Actual>
static
std::auto_ptr<Base> create_func() {
return std::auto_ptr<Base>(new Actual());
}
private:
typedef std::map<Key, Creator> Registry;
Registry _registry;
};
This is not meant to be the best in every circumstance, but it is intended to be a first approximation and a more useful default than manually implementing the type of function stijn mentioned. 这并不意味着在每种情况下都是最好的,但它的目的是作为第一个近似和一个比手动实现所提到的函数类型更有用的默认值。 How each hierarchy should register itself isn't mandated by Factory, but you may like the method gf mentioned (it's simple, clear, and very useful, and yes, this overcomes the inherent problems with macros in this case). 每个层次结构应该如何注册本身并不是Factory规定的,但是你可能会喜欢上面提到的方法 (它简单,清晰,非常有用,是的,这可以克服宏在这种情况下的固有问题)。
Here's a simple example of the factory: 这是工厂的一个简单示例 :
struct Base {
typedef ::Factory<Base> Factory;
virtual ~Base() {}
virtual int answer() const = 0;
static Factory::Type create(Factory::Key const& name) {
return _factory.create(name);
}
template<class Derived>
static void define(Factory::Key const& name) {
bool new_key = _factory.define(name,
&Factory::template create_func<Base, Derived>);
if (not new_key) {
throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
": name already registered");
}
}
private:
static Factory _factory;
};
Base::Factory Base::_factory;
struct A : Base {
virtual int answer() const { return 42; }
};
int main() {
Base::define<A>("A");
assert(Base::create("A")->answer() == 42);
return 0;
}
the quickest yet very usable way in a lot of areas, would be something like 在许多领域中最快捷但非常有用的方式就像是
Base* MyFactoryMethod( const std::string& sClass ) const
{
if( sClass == "A" )
return CreateNewA();
else if( sClass == "B" )
return new CreateClassB();
//....
return 0;
}
A* CreateClassA() const
{
return new A();
}
You could also look into the Boost class factory implementation. 您还可以查看Boost类工厂实现。
Here's a simple example using the Boost factory method and class registration: 这是一个使用Boost工厂方法和类注册的简单示例:
typedef boost::function<Parent*()> factory;
// ...
std::map<std::string, factory> factories;
// Register derived classes
factories["Child1"] = boost::factory<Child1*>();
factories["Child2"] = boost::factory<Child2*>();
// ...
// Instantiate chosen derived class
auto_ptr<Parent> pChild = auto_ptr<Parent>(factories["Child1"]());
First off, yes, that is just what the factory pattern is for. 首先,是的,这就是工厂模式的用途。
(By the way, your other idea is a possible implementation of the factory pattern) (顺便说一下,你的另一个想法是工厂模式的可能实现)
If you intend to do this for a large project (if not, just go with stijns answer ), you might want to consider using an associative container somewhere instead of explicit branching and maybe even moving the registration responsibility into the classes to 如果你打算为一个大项目做这个(如果没有,只需要使用stijns答案 ),你可能想考虑在某处使用关联容器而不是显式分支,甚至可能将注册责任移到类中
To achieve convenient registration in the classes you could use something like this suggestion and add a function pointer or a functor to the entries that instantiates the derived class and returns a pointer to the base. 为了在类中实现方便的注册,您可以使用类似于此建议的内容,并向实例化派生类的条目添加函数指针或函子 ,并返回指向基类的指针。
If you're not afraid of macros you can then add classes to the factory by just adding one tiny macro to its declaration. 如果您不害怕宏,则可以通过在其声明中添加一个小宏来向工厂添加类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.