Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于抽象工厂和注射的问题_C++_Design Patterns_Oop - Fatal编程技术网

C++ 关于抽象工厂和注射的问题

C++ 关于抽象工厂和注射的问题,c++,design-patterns,oop,C++,Design Patterns,Oop,这和我的另一个问题很相似,但我认为这两个问题的不同之处足以让我提出一个新的问题 基本上,我正在编写一个用户界面,我的用户界面有可以选择的节点。选择节点后,用户界面将以抽象节点基类“INode”结束。通过执行node->getFactory(),我得到了一个工厂,我可以由此为该节点创建适当的对话框或视图,因为具体节点返回了正确的工厂(例如factory->createAddDialog(),factory->createView(node),等等) 我的问题是,首先尝试找到工厂进入节点的最佳方式

这和我的另一个问题很相似,但我认为这两个问题的不同之处足以让我提出一个新的问题

基本上,我正在编写一个用户界面,我的用户界面有可以选择的节点。选择节点后,用户界面将以抽象节点基类“INode”结束。通过执行node->getFactory(),我得到了一个工厂,我可以由此为该节点创建适当的对话框或视图,因为具体节点返回了正确的工厂(例如factory->createAddDialog(),factory->createView(node),等等)

我的问题是,首先尝试找到工厂进入节点的最佳方式

到目前为止,我已经想到了三种方法:

1) 创建节点时注入正确的工厂:

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();
    ...
}