简体   繁体   English

使用工厂模式按名称实例化类

[英]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类工厂实现。

  • If there's only a few derived classes you can use an "if, else" list. 如果只有少数派生类,则可以使用“if,else”列表。
  • If you plan to have many derived classes it's better to sort out the class registration process (as Georg mentioned) than to use an "if, else" list. 如果你计划有很多派生类,最好整理类注册过程(如Georg所提到的),而不是使用“if,else”列表。

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答案 ),你可能想考虑在某处使用关联容器而不是显式分支,甚至可能将注册责任移到类中

  • avoid code changes in one additional place (your factory) 避免在一个额外的地方(您的工厂)更改代码
  • and in turn avoid possibly very long recompilation times (for in-header-implementations ) when adding a class 并且在添加类时反过来避免可能很长的重新编译时间(对于in-header-implementation

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.

相关问题 模板类的工厂模式和模板类的新类型默认参数 - Factory Pattern for Template Classes and Default Argument of New Type for Template Classes 虚拟函数中具有更改参数/返回类型的子类的工厂模式 - Factory pattern for child classes with changing parameter/ return types in virtual functions 使用模板参数实例化模板类 - Instantiating template classes with template parameters 实例化子类的多态问题 - Polymorphism issue with instantiating sub classes 将工厂用于使用多个内存池的类是否合适? 有更好的模式/技术吗? - Is it appropriate to use a factory for classes that use multiple memory pools? Is there a better pattern/technique? 具有抽象基类的工厂模式-通过ref还是按值返回? 范围界定和切片问题 - Factory pattern with abstract base classes - return by ref or by value? Problems with scoping and slicing LNK1120类错误(工厂模式)。 不知道它来自哪里 - LNK1120 error with classes (Factory pattern). Not sure where it's coming from 使用来自不同类的同名函数; 这是什么模式? - Using functions with the same name from different classes; what pattern is this? 如何实现工厂模式? - How to implement Factory pattern? “工厂”方法是否正确? - Is a “factory” method the right pattern?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM