C++ 关于抽象工厂和注射的问题
这和我的另一个问题很相似,但我认为这两个问题的不同之处足以让我提出一个新的问题 基本上,我正在编写一个用户界面,我的用户界面有可以选择的节点。选择节点后,用户界面将以抽象节点基类“INode”结束。通过执行node->getFactory(),我得到了一个工厂,我可以由此为该节点创建适当的对话框或视图,因为具体节点返回了正确的工厂(例如factory->createAddDialog(),factory->createView(node),等等) 我的问题是,首先尝试找到工厂进入节点的最佳方式 到目前为止,我已经想到了三种方法: 1) 创建节点时注入正确的工厂:C++ 关于抽象工厂和注射的问题,c++,design-patterns,oop,C++,Design Patterns,Oop,这和我的另一个问题很相似,但我认为这两个问题的不同之处足以让我提出一个新的问题 基本上,我正在编写一个用户界面,我的用户界面有可以选择的节点。选择节点后,用户界面将以抽象节点基类“INode”结束。通过执行node->getFactory(),我得到了一个工厂,我可以由此为该节点创建适当的对话框或视图,因为具体节点返回了正确的工厂(例如factory->createAddDialog(),factory->createView(node),等等) 我的问题是,首先尝试找到工厂进入节点的最佳方式
AreaNode *node = new AreaNode(new AreaNodeFactory());
因此,AreaNode的定义是:
AreaNode : public INode
{
AreaNode(INodeAbstractFactory *injectedFactory)
{
m_injectedFactory = injectedFactory;
}
INodeAbstractFactory* getFactory()
{
return m_injectedFactory;
}
INodeAbstractFactory* m_injectedFactory;
};
2) 注入更一般的工厂,并允许节点从该工厂获取工厂:
AreaNode : public INode
{
AreaNode(IFactory *injectedFactory)
{
m_injectedFactory = injectedFactory;
}
INodeAbstractFactory* getFactory()
{
return m_injectedFactory->getAreaNodeFactory();
}
IFactory* m_injectedFactory;
}
3) 只需创建一个具体的工厂(尽管这会删除为同一节点使用不同工厂的范围,可能是为了测试或以后的更改):
关于这些选择的当前想法:
选项1:可能有点随意-我必须确保始终为该类型提供正确的工厂,或者我可以使用其他工厂为我注入正确的工厂
选项2:强制节点充分了解抽象工厂实现,以便能够调用getAreaNodeFactory,这可能不是一件坏事。它至少有助于确保始终获取正确/相同的工厂(假设正确实现了更通用的工厂)
选项3:这感觉没有什么限制,因为我无法交换类,而且我不希望节点必须了解工厂的具体实现——尽管在这种情况下,这可能不是一个太大的问题(著名的遗言!)
有什么想法吗
谢谢
编辑:
很抱歉,在origin帖子中遗漏了变量声明,已更正
编辑:
选项2的另一个问题是我必须在每个节点类型中实现“getFactory”。至少在选项1中,基类每次都可以返回inject抽象工厂类。怎么样
template<typename Factory>
class AreaNode : public INode
{
public:
virtual ~AreaNode(){}
AreaNode() : pFactory_(new Factory())
{
}
const shared_ptr<IFactory>& GetFactory()
{
return pFactory_;
}
private:
shared_ptr<IFactory> pFactory_;
};
模板
类AreaNode:公共索引节点
{
公众:
虚拟~AreaNode(){}
AreaNode():pFactory(新工厂())
{
}
const shared_ptr&GetFactory()
{
返回工厂;
}
私人:
共享工厂;
};
编辑:
或者取决于你的背景
template<typename Factory>
class Node
{
public:
virtual ~Node(){}
Node() : pFactory_(new Factory())
{
}
const shared_ptr<IFactory>& GetFactory()
{
return pFactory_;
}
private:
shared_ptr<IFactory> pFactory_;
};
class AreaNode : public Node<AreaNodeFactory>
{
// Implementation
};
// OR
typedef Node<AreaNodeFactory> AreaNode;
模板
类节点
{
公众:
虚拟~Node(){}
Node():pFactory_389;(新工厂())
{
}
const shared_ptr&GetFactory()
{
返回工厂;
}
私人:
共享工厂;
};
类别AreaNode:公共节点
{
//实施
};
//或
类型定义节点区域节点;
怎么样
class FactoryBase { /* interface */ }
template <typename NodeType> class Factory : public FactoryBase {
// Default implementation.
}
// Add appropriate specializations for all relevant nodetypes, if needed.
template <typename NodeType> inline Factory<NodeType> getFactory(NodeType*) {
return Factory<NodeType>( );
}
class AreaNode : public Node {
FactoryBase getFactory() { return getFactory(this); }
};
取决于“节点”对象的用途 如果一个工厂应该被注入到一个节点中,而具体的节点不需要对工厂的具体类型做任何事情,那么所有与工厂相关的代码都可以被移动到基本的节点类中,从而简化了一切
class INode //well, it's not "interface" in clear sense
{
public:
void setFactory(Factory* f) { this->f = f; }
Factory* getFactory() const { return f; }
private:
Factory* f;
};
现在,混凝土节点和混凝土工厂的功能相互正交,可以以任何方式自由组合
如果一个具体类型的节点绑定到一个具体类型的工厂,那么您可能应该完全避免工厂,直接使用node::createView方法创建视图。这取决于工厂是否在其他环境中使用
template<typename Factory>
class Node
{
public:
virtual ~Node(){}
Node() : pFactory_(new Factory())
{
}
const shared_ptr<IFactory>& GetFactory()
{
return pFactory_;
}
private:
shared_ptr<IFactory> pFactory_;
};
class AreaNode : public Node<AreaNodeFactory>
{
// Implementation
};
// OR
typedef Node<AreaNodeFactory> AreaNode;
也考虑这一点(不太OO-ISH方式):
typedef boost::function0节点;
std::映射节点;
节点[area_item1]=&getAreaFactory;
节点[area_item2]=&getAreaFactory;
节点[region_item1]=&getRegionFactory;
...
选择无效(UIItem*i)
{
...
视图*v=节点[i]()->createView();
...
}
也许,它可以满足您的所有需要)我甚至不确定节点是否应该引用工厂。用户界面应该引用一个抽象工厂,并且应该使用多态性来确保使用了正确的具体工厂,这取决于传递到create方法中的节点类型。除此之外,我认为选项1看起来还可以。但我仍然相信节点不应该知道或持有对任何工厂的引用。@Kurt:在没有双重分派的情况下,避免对每个用户界面“操作”使用访问者类,我希望根据节点的类型在节点上执行,有什么更好的解决方案?我希望在节点上执行的操作类型大致如下:createAddDialog(parentWidget)、createView(parentWidget)、createMiniView(parentWidget)等。我可以将这些方法放在具体的节点类中,即areaNode->createView(parent)-但这对分离没有多大作用。虽然我试图避免大量使用访问者模式,但我能看到的唯一方法是完全将节点排除在UI端之外,即使用单个访问者来解析适当的工厂类,从那时起,我可以创建我的UI组件。我试图阻止节点拥有这样的方法-让节点“知道”诸如“createView”之类的方法似乎有点错误,但也许我错了。单个节点类型不会。他们只是参考工厂。API详细信息仅限于基类,它存在于基类中,用于将
this
传递给工厂方法。好的,我明白你的意思-另一方面,上面库尔特的评论是节点不应该引用任何工厂-所以我再次感到痛苦。最初,我使用访问者进行双重调度,但每次操作都使用它们太麻烦了,而且由于节点类型的数量,它们变得非常庞大。好主意——不过,即使知道工厂,你对节点的整体概念有何看法?上面的库尔特认为这是个坏主意,怎么说
class INode //well, it's not "interface" in clear sense
{
public:
void setFactory(Factory* f) { this->f = f; }
Factory* getFactory() const { return f; }
private:
Factory* f;
};
typedef boost::function0<Factory*> Node;
std::map<UIItem*,Node> nodes;
nodes[area_item1] = &getAreaFactory;
nodes[area_item2] = &getAreaFactory;
nodes[region_item1] = &getRegionFactory;
...
void OnSelect(UIItem* i)
{
...
View* v = nodes[i]()->createView();
...
}