我的库使用对象工厂技术来创建具有特定目的的“节点”。默认情况下,这些节点可以完成它们的工作但非常基本。我希望允许我的库的用户能够创建所提供的“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()”函数的好奇心,用户可以注册他们的子类以便工厂创建而不是基础 - 我提供的课程。
编辑:
更简洁的方式来表达问题如下:如果用户已经定义了一个子类而不是我的默认基类,我怎样才能让用户告诉工厂创建子类的实例?我想再次感谢大家回答这个问题的时间和精力。
答案 0 :(得分:2)
工厂模式用于创建具有间接引用的对象。例如,用户应该可以调用:
Node* node = Factory::createNode("MyNodeType");
如果有一个Factory可以创建这样一个Node,那么该函数将返回一个指向MyNodeType
对象的指针。否则,它返回NULL。
为了使此功能起作用,必须注册Factory
,可以构造MyNodeType
类型的对象。我们必须相信这样的工厂会创建该类型的节点。
这个模式涉及的课程:
Node
。Factory
。Node
的具体子类MyNodeType
。Factory
的子类。我们称之为MyNodeTypeFactory
。这是一个骨架结构。
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)
我认为这里的问题是结合以下两个要求:
现在我建议的是类似于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成为一个虚函数)并让它生成所需类型的节点。当然,您必须将节点向量移动到不同的类中。