2013-05-13 15 views
9

Sono bloccato con un problema di duplicazione del codice, relativo al modello di visitatore per un albero. La situazione attuale è la seguente: Ho un albero, costituito da due diverse classi di nodi, ad esempio foglie e non foglia. Inoltre, ho due classi base di visitatori che sembrano molto simili, tranne che per le visite agli alberi const e agli altri alberi non const. Le azioni effettive che i visitatori concreti devono fare sono indipendenti dai tipi concreti del nodo. Vi darò un breve esempio:Modello di visitatore per le versioni const e nonconst di un albero

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

classi visitatori calcestruzzo ereditano sia da Visitor o da ConstVisitor, a seconda che il loro metodo processNode deve alterare i nodi visitati o no.

Si vede, c'è un sacco di duplicazione del codice tra i due visitatori e poiché dovrò implementare un'altra strategia di attraversamento, anche per i nodi const e nonconst, voglio evitare quella duplicazione. Ci sono possibilità di estrarre il codice duplicato, preferibilmente senza usare const_cast dappertutto?

risposta

11

Si potrebbe definire un modello di TVisitor classe come fatto qui di seguito:

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

E poi usare Visitor e ConstVisitor come tipo alias per istanze di quel modello classe corrispondente:

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

Grazie, è stato veloce e soluzione pulita. Spero che i miei colleghi non odino troppo i modelli ;-) –

+0

@ArneMertz: Va bene, buona fortuna per il tuo progetto;) –

0

si potrebbe usare i modelli :

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