迭代节点层次结构 - 访问者模式和组合模式?

8
让我们假设我有一个节点集合,稍后将用于我的渲染器类。然后我有一个访问者类,可以访问节点或整个集合。这很简单,因为我的节点集合只是一个带有一些额外方法的std :: list包装器。
问题是,我想为节点(而不是简单列表)拥有树形结构,以便一个节点可以有一个父节点和n个子节点。这将非常方便,因为我想能够向我的渲染器传递一个节点并渲染该节点“下面”的所有内容。答案可能是Composite。
如何同时使用Visitor和Composite?我已经阅读过它们通常是一个好组合,但我的实现看起来相当糟糕...我错过了什么。
3个回答

5
我已经在我们的系统中实现了非常类似的东西。我想要一种方法来组合几何对象的层次结构并将它们渲染到体积中。我使用组合模式来组合我的描述(根节点是Node,然后派生子节点是compositeNode(Nodes列表)。
CompositeNode有一个接受访问者(Visitor)的方法accept(),然后在accept()中你可以执行visitor->visit(this)。
因此,您的访问者层次结构具有基类NodeVisitor和派生访问者,如RenderVisitor(渲染对象),ReportVisitor(将节点信息转储为文本)。您的基类需要接受基本和专业节点类型。
所以,组合确实有效,我有可工作的代码,但我同意设计需要比你在网上阅读的更多的努力(维基或玩具示例)。
希望这可以帮助到您。

3
这是一个简单的例子:
struct NodeVisitor;

struct Node
{
  virtual ~Node() {}
  virtual void accept(NodeVisitor &v);
};

struct CompositeNode : public Node
{
  virtual void accept(NodeVisitor &v);
  std::list<NodePtr> nodes_;
};

struct NodeVisitor
{
  virtual ~NodeVisitor() {}
  virtual void visit(Node &n) = 0;
  virtual void visit(CompositeNode &cn)
  {
    for(std::list<NodePtr>::iterator it = cn.nodes_.begin(), end = cn.nodes_.end(); it != end; ++it)
    {
      (*it)->accept(*this);
    }
  }
};

为什么你在NodeVisitor中调用节点子元素的accept方法? - user35443
@user35443:否则访问将停止,由于OP要求如何将Visitor与Composite结合,这需要包括对Composite中所有节点的访问,否则它只是Visitor。有关Visitor的信息:http://en.wikipedia.org/wiki/Visitor_pattern。有关Composite的信息:http://en.wikipedia.org/wiki/Composite_pattern。 - Andreas Magnusson
是的,但我的意思是我已经看了一段时间的层次结构,无论我看到哪里,我都发现节点中的复合成员迭代,而不是访问者。 - user35443
@user35443:嗯,你可以用任何一种方式来实现。每种方式都有其优缺点。在访问者中进行迭代可以给你更多的灵活性。在组合节点中进行迭代可以让你只需编写一次代码就可以忘记它。通常在我遇到的大多数实际情况中,我需要那种额外的灵活性。 - Andreas Magnusson

1
如果您希望访问者了解树的结构(例如,正在访问的深度或从树根的路径),则可以考虑使用分层访问者模式。这在c2.com wiki上有详细介绍。
它还展示了如何跳过“无趣”的分支。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接