2013-05-13 7 views
9

Ich bin mit einem Code Duplikationsproblem fest, in Bezug auf das Besuchermuster für einen Baum. Die aktuelle Situation ist wie folgt: Ich habe einen Baum, der aus zwei verschiedenen Knotenklassen besteht, nämlich Blättern und Nicht-Blättern. Außerdem habe ich zwei Besucherbasisklassen, die sehr ähnlich aussehen, außer dass man Konstantenbäume und die anderen nicht-konstanten Bäume besucht. Die tatsächlichen Aktionen, die die konkreten Besucher ausführen müssen, sind unabhängig von den konkreten Typen des Knotens. Ich werde ein kurzes Beispiel:Besuchermuster für const und nonconst Versionen eines Baumes

class Visitor; 
class ConstVisitor; 

class Node { 
public: 
    virtual void accept(Visitor&) = 0; 
    virtual void accept(ConstVisitor&) const = 0; 
}; 

class Leaf : public Node { 
    virtual void accept(Visitor& v)  {v.visitLeaf(*this);} 
    virtual void accept(ConstVisitor& cv) {cv.visitLeaf(*this);} 
}; 

class CompoundNode : public Node { 
public: 
    vector<Node*> getChildren() const; 
    virtual void accept(Visitor& v)  {v.visitCompoundNode(*this);} 
    virtual void accept(ConstVisitor& cv) {cv.visitCompoundNode(*this);} 
}; 

class Visitor { 
protected: 
    virtual void processNode(Node& node) = 0; 
public: 
    void visitLeaf(Leaf& leaf) { 
    processNode(leaf); 
    } 
    void visitCompoundNode(CompoundNode& cNode) { 
    processNode(cNode); 
    auto children = cNode.getChildren(); 
    for (auto child : children) 
     child->accept(this); 
    } 
}; 

class ConstVisitor { 
protected: 
    virtual void processNode(Node const& node) = 0; 
public: 
    void visitLeaf(Leaf const& leaf) { 
    processNode(leaf); 
    } 
    void visitCompoundNode(CompoundNode const& cNode) { 
    processNode(cNode); 
    auto children = cNode.getChildren(); 
    for (auto child : children) 
     child->accept(this); 
    } 
}; 

Konkrete Besucher Klassen erben entweder aus Visitor oder von ConstVisitor, je nachdem, ob ihre processNode Methode der Knoten besucht zu verändern hat oder nicht.

Sie sehen, es gibt eine Menge Code-Duplizierung zwischen den beiden Besuchern, und da ich eine andere Traversal-Strategie implementieren muss, auch für Const und Nonconst-Knoten, möchte ich diese Duplizierung vermeiden. Gibt es irgendwelche Möglichkeiten, den doppelten Code zu extrahieren, vorzugsweise ohne const_cast überall zu verwenden?

Antwort

11

Sie könnten eine TVisitor Klassenvorlage definieren, wie unten getan:

#include <type_traits> 

class Node; 
class CompoundNode; 
class Leaf; 

template<bool isNonConstVisitor> 
class TVisitor 
{ 
    typedef typename std::conditional<isNonConstVisitor, 
     Node, Node const>::type node_type; 

    typedef typename std::conditional<isNonConstVisitor, 
     CompoundNode, CompoundNode const>::type compound_node_type; 

    typedef typename std::conditional<isNonConstVisitor, 
     Leaf, Leaf const>::type leaf_node_type; 

protected: 

    virtual void processNode(node_type& node) = 0; 

public: 

    void visitLeaf(leaf_node_type& leaf) { processNode(leaf); } 

    void visitCompoundNode(compound_node_type& cNode) { 
     processNode(cNode); 
     auto children = cNode.getChildren(); 
     for (auto child : children) { child->accept(*this); } 
    } 
}; 

Und dann Visitor und ConstVisitor als Typ-Aliasnamen verwenden für instantiations dieser Klasse Vorlage entsprechen:

typedef TVisitor<true> Visitor; 
typedef TVisitor<false> ConstVisitor; 
+0

Danke, das war eine schnelle und saubere Lösung. Ich hoffe meine Kollegen hassen Vorlagen nicht zu sehr ;-) –

+0

@ArneMertz: Alles klar, viel Glück mit deinem Projekt;) –

0

Sie Vorlagen verwenden könnten :

template<typename NodeType, 
     typename CompoundNodeType, 
     typename LeafType> 
class BaseVisitor { 
protected: 
    virtual void processNode(NodeType& node) = 0; 
public: 
    void visitLeaf(LeafType& leaf) { 
     processNode(leaf); 
    } 
    void visitCompoundNode(CompoundNodeType& cNode) { 
     processNode(cNode); 
     auto children = cNode.getChildren(); 
     for (auto child : children) 
     child->accept(this); 
    } 
}; 

class Visitor: public BaseVisitor<Node, CompoundNode, Leaf> { 
}; 

class ConstVisitor: public BaseVisitor<const Node, const CompoundNode, const Leaf> { 
};