2013-05-13 24 views
9

Utknąłem z problemem powielania kodu, w odniesieniu do wzorca odwiedzającego dla drzewa. Obecna sytuacja wygląda następująco: Mam drzewo, składające się z dwóch różnych klas węzłów, tj. Liści i nie-liści. Ponadto mam dwie klasy baz danych odwiedzających, które wyglądają bardzo podobnie, oprócz tego, że odwiedza się drzewa const i inne niestanowiące drzewa. Rzeczywiste działania, które muszą wykonać konkretni goście, są niezależne od konkretnych typów węzłów. Podam krótki przykład:Wzorce odwiedzin dla stałych i niepasujących wersji drzewa

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

zajęcia gości betonowe odziedziczyć albo z Visitor lub ConstVisitor, w zależności od tego, czy ich metoda processNode musi zmieniać węzły odwiedził czy nie.

Widzisz, istnieje wiele powielania kodu między dwoma odwiedzającymi i ponieważ będę musiał wdrożyć inną strategię przejścia, także dla węzłów stałych i stałych, chcę uniknąć tego duplikowania. Czy są jakieś możliwości wyodrębnienia duplikatu kodu, najlepiej bez używania const_cast w każdym miejscu?

Odpowiedz

11

Można zdefiniować szablon TVisitor klasy jak zrobić poniżej:

#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); } 
    } 
}; 

a następnie użyć Visitor i ConstVisitor jako typ aliasów dla odpowiadających dawałaby tej klasy szablonu:

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

Dzięki, to był szybki i czyste rozwiązanie. Mam nadzieję, że moi koledzy nie nienawidzą szablonów zbyt wiele ;-) –

+0

@ArneMertz: W porządku, powodzenia w projekcie;) –

0

można użyć szablonów :

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> { 
};