假设我有一个类A, B, C, ...
的列表,这些类都继承自Base
。
我从用户那里得到类名作为字符串,我想实例化正确的类并返回指向Base
的指针。你会如何实现这个?
我想过使用带有类名作为键的哈希表,以及一个指向实例化正确类并返回Base *
的函数的函数指针。
但是,我想我可以在这里使用工厂模式并使其更容易,但我不能很好地记住它,所以我虽然要求建议。
答案 0 :(得分:7)
这是一个通用的factory example实现:
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;
};
这并不意味着在所有情况下都是最好的,但它的目的是作为第一个近似值,并且比手动实现所提到的函数类型更有用。每个层次结构应该如何注册自己并不是Factory规定的,但是你可能会喜欢提到的method gf(它简单,清晰,非常有用,是的,这可以克服宏在这种情况下的固有问题)。
这是工厂的simple example:
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;
}
答案 1 :(得分:3)
在许多领域中最快但非常有用的方式,就像
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();
}
答案 2 :(得分:2)
您还可以查看Boost类factory实现。
以下是使用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"]());
答案 3 :(得分:1)
首先,是的,这就是工厂模式的用途 (顺便说一句,你的另一个想法是工厂模式的可能实现)
如果您打算为大型项目执行此操作(如果不是,请使用stijns answer),您可能需要考虑在某处使用关联容器而不是显式分支,甚至可能会移动注册责任进入课程
为了在类中方便地注册,您可以使用类似this suggestion的内容,并在实例化派生类的条目中添加函数指针或functor,并返回指向基类的指针。 /> 如果你不害怕宏,你可以通过在声明中添加一个小宏来为工厂添加类。