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.
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
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);
}
}
};
If you want your visitor also to know the structure of the tree (e.g. the depth it is visiting or the path from the tree root) you could consider using the hierarchical visitor pattern.
This is described somewhat lengthy at c2.com wiki
It also shows how to skip an 'uninteresting' branch.