自定义对象工厂

时间:2014-06-14 02:40:03

标签: c++ c++11 factory factory-pattern

我的库使用对象工厂技术来创建具有特定目的的“节点”。默认情况下,这些节点可以完成它们的工作但非常基本。我希望允许我的库的用户能够创建所提供的“Node”类的子类来定义他们自己的功能,同时保持节点的基本功能不变。 以下是一些示例代码来演示我的问题:

class Node
{
    int SomeValue;
public:
    Node(int Value)
    {
        SomeValue = Value;
    }

    ~Node()
    {
        // Cleanup the node
    }
};

class NodeFactory
{
    std::vector<Node*> Nodes;
public:
    void CreateNode(int Value)
    {
        Nodes.push_back(new Node(Value));
    }
};

这显示了基本的Object Factory技术,现在我的问题。 我可以向“NodeFactory”添加一个函数,例如“void SetType()”,并且能够传入“Node”的子类,而“Node”又会在“CreateNode”函数中创建该子类吗?

非常感谢您的时间,非常感谢。

编辑:

“void CreateNode()”的使用从最终用户抽象出来,因此我对“void RegisterType()”函数的好奇心,用户可以注册他们的子类以便工厂创建而不是基础 - 我提供的课程。

编辑:

更简洁的方式来表达问题如下:如果用户已经定义了一个子类而不是我的默认基类,我怎样才能让用户告诉工厂创建子类的实例?我想再次感谢大家回答这个问题的时间和精力。

4 个答案:

答案 0 :(得分:2)

工厂模式用于创建具有间接引用的对象。例如,用户应该可以调用:

Node* node = Factory::createNode("MyNodeType");

如果有一个Factory可以创建这样一个Node,那么该函数将返回一个指向MyNodeType对象的指针。否则,它返回NULL。

为了使此功能起作用,必须注册Factory,可以构造MyNodeType类型的对象。我们必须相信这样的工厂会创建该类型的节点。

这个模式涉及的课程:

  1. 抽象基类Node
  2. 抽象基类Factory
  3. Node的具体子类MyNodeType
  4. 创建Factory的子类。我们称之为MyNodeTypeFactory
  5. 这是一个骨架结构。

    Node.h:

    class Node
    {
       virtual ~Node() = 0;
    };
    

    Factor.h:

    #include <string>
    
    class Factory
    {
       public:
    
          static void registerFactory(std::string const& productType,
                                      Factory* factory);
    
          static Node* creatNode(std::string const& productType);
    
       private:
    
          virtual Node* createNode();
    };
    

    Factory.cc:

    #include <map>
    
    typedef std::map<std::string, Factory*> FactoryMap;
    
    static FactoryMap& getFactoryMap()
    {
       static FactoryMap factoryMap;
       return factoryMap;
    }
    
    static void registerFactory(std::string const& productType,
                                Factory* factory)
    {
       getFactoryMap()[productType] = factory;
    }
    
    static Node* creatNode(std::string const& productType)
    {
       FactoryMap& factoryMap = getFactoryMap();
       FactoryMap::iterator iter = factoryMap.find(productType);
       if ( iter == factoryMap.end() )
       {
          // Unknown product.
          return NULL;
       }
    
       return iter->second->createNode();
    }
    

    MyNodeType.h:

    #include "Node.h"
    class MyNodeType : public Node
    {
       MyNodeType() {}
       virtual ~MyNodeType() {}
    };
    

    MyNodeTypeFactory.h:

    #include <Factory.h>
    
    class MyNodeTypeFactory : public Factory
    {
       public:
    
          virtual Node* createNode();
    };
    

    MyNodeTypeFactory.cc:

    #include "MyNodeTypeFactory.h"
    
    struct RegistrationHelper
    {
       MyNodeTypeFactorHelper()
       {
          Factory::registerFactory("MyNodeType", new MyNodeTypeFactory());
       }
    };
    
    static RegistrationHelper helper;
    
    Node* MyNodeTypeFactory::createNode()
    {
       return MyNodeType();
    }
    

答案 1 :(得分:2)

我认为这里的问题是结合以下两个要求:

  1. 您希望使用非常简单的函数void CreateNode(int)来创建任何节点。
  2. 您希望用户能够创建从Node派生的新节点,并使用您的工厂来创建它们。
  3. 现在我建议的是类似于R Sahu的东西,但是没有像他那样严格遵守工厂模式。

    您可以通过要求用户将小型Creator对象传递给您的工厂来获得您所寻求的功能。 (请注意,这与经典的Factory模式略有不同。因为您基本上使用creator-classes将NodeFactory变为委托者。)

    class NodeCreator {
    public:
       virtual Node* create(int) = 0;
       virtual ~NodeCreator() = default;  
    };
    
    class DefaultNodeCreator : public NodeCreator {
    public:
       virtual Node* create(int value) {
          return new Node(value);
       }
    };
    

    现在我作为用户将创建自己的节点:

    class MyNode : public Node {
    private:
       int otherValue;
    public:
       MyNode(int nodeValue, int otherValue ) 
          : Node(nodeValue), otherValue(otherValue) 
       {}
       // Implement other functionality...
    };
    
    class MyNodeCreator : public NodeCreator { 
    private:
       // I added otherNodeValue to show that Creators can have a state.
       int otherNodeValue; 
    public:
       MyNodeCreator(int otherNodeValue ) : otherNodeValue(otherNodeValue) {}
       virtual Node* create(int value) {
          return new MyNode(value, otherNodeValue);
       }
    };
    

    现在终于在你的Factory类中你需要像这样设置它:

    class NodeFactory
    {
       std::vector<Node*> Nodes;
       std::unique_ptr<NodeCreator> activeCreator;
    
    public:
       NodeFactory() {
          setNodeCreator(nullptr);
       }
    
       void createNode(int Value)
       {
           Nodes.push_back( activeCreator->create(Value) );
       }
    
       void setNodeCreator( std::unique_ptr<NodeCreator> creator ) {
          if (creator == nullptr) { 
             activeCreator.reset( new DefaultNodeCreator() );
          else {
             activeCreator.reset(creator);
          }
       }
    };
    

    从main使用它:

    int main() {
       NodeFactory nf;
    
       nf.createNode(1); // Creating Node(1)
       nf.createNode(2); // Creating Node(2)
    
       nf.setCreator( new MyNodeCreator(5) );
       // Any nodes created now will be of type MyNode 
       // with otherNodeValue == 5.
    
       nf.createNode(2); // Creating MyNode(2, 5)
       nf.createNode(3); // Creating MyNode(3, 5)
    }
    

    最后一点:

    如果您打算让您的用户实现Node的子类并将其与多态一起使用,如上所示,那么将Node的析构函数声明为virtual是很重要的。您无法保证您的用户不会在其子类中使用动态分配,因此您有责任确保调用其析构函数。

答案 2 :(得分:0)

您甚至可能不需要RegisterType() ...最简单的方法是使用C ++ 11(它允许您派生与基本节点,构造函数签名不同的节点): / p>

#include <iostream>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>

class Node
{
    int SomeValue;

public:
    Node(int Value)
      : SomeValue{Value}
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    // ATTENTION Make destructor virtual!
    virtual ~Node()
    {
        // Cleanup the node
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class SomeOtherNode : public Node
{
    std::string SomeStringValue;

public:
    SomeOtherNode(int Value, const std::string StringValue)
      : Node{Value}
      , SomeStringValue{StringValue}
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    ~SomeOtherNode()
    {
        // Cleanup the string node
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class NotARealNode
{
    int SomeValue;

public:
    NotARealNode(int Value)
      : SomeValue{Value}
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    ~NotARealNode()
    {
        // Cleanup the node
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class NodeFactory
{
    std::vector<std::unique_ptr<Node>> Nodes;

public:
    template <typename NodeType, typename... Args>
    typename std::enable_if<
        std::is_base_of<Node, NodeType>::value
      >::type CreateNode(Args&&... args)
    {
        Nodes.push_back(
            std::unique_ptr<NodeType>{
                new NodeType{std::forward<Args>(args)...}
              }
          );
    }
};

int main()
{
    NodeFactory f;
    f.CreateNode<Node>(123);
    f.CreateNode<SomeOtherNode>(123, "Hello");
#if 0
    // ATTENTION It wont compile, cuz NotARealNode is not a child of Node!
    f.CreateNode<NotARealNode>(123);
#endif
    return 0;
}

输出:

zaufi@gentop>/work/tests> g++ -std=c++11 -o fff fff.cc
zaufi@gentop>/work/tests> ./fff
Node::Node(int)
Node::Node(int)
SomeOtherNode::SomeOtherNode(int, std::string)
virtual Node::~Node()
virtual SomeOtherNode::~SomeOtherNode()
virtual Node::~Node()

答案 3 :(得分:0)

你可以(应该?)使用多态性。只需从NodeFactory派生(使CreateNode成为一个虚函数)并让它生成所需类型的节点。当然,您必须将节点向量移动到不同的类中。