views:

235

answers:

2

Let's imagine I have a collection of nodes that I use for my Renderer class later on. Then I have a Visitor class that can visit node or whole collection. It's simple because my collection of nodes it's simply a wrapper to the std::list with few extra methods.

The problem is I'd like to have a tree like structure for nodes(instead of simple list) so a node can have a parent and n children. That would be handy as I'd like to be able to pass to my Renderer a node and render everything "below" that node. The answer probably is Composite.

How can I use together Visitor and Composite? I've read that its often a good combo but my implementations look pretty bad... I'm missing sth.

+2  A: 

I have something very similar implemented for our system. I wanted a way to compose hierarchy of geometrical object and render them into the volume. I used composite pattern to compose my description (root was Node and then derived child was compositeNode (list of Nodes).

CompositeNode has method accept() which accepts a visitor (Visitor) and then inside the accept() you do visitor->visit(this).

Thus your visitor hierarchy has base class as NodeVisitor and derived visitors like RenderVisitor (renders objects), ReportVisitor (dumped node info into text). Your base class will need to accept both base and specialized node types.

So yes, combo works and I have working code but I agree that design takes more effort than what you would read online (Wiki or toy example).

Hope this helps

Ketan
+1  A: 

Here's a simple example:

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);
    }
  }
};
Andreas Magnusson