2013-05-13 5 views
9

트리의 방문자 패턴과 관련하여 코드 중복 문제가 있습니다. 현재 상황은 다음과 같습니다. 두 개의 다른 노드 클래스 (leafs와 non-leafs)로 구성된 트리가 있습니다. 또한 나는 const tree와 다른 non-const trees를 방문한다는 점을 제외하면 매우 비슷하게 보이는 두 개의 방문자 기반 클래스를 가지고 있습니다. 구체적인 방문자가해야하는 실제 작업은 노드의 구체적인 유형과 독립적입니다. 나는 간단한 예제를주지 :트리의 const 및 nonconst 버전에 대한 방문자 패턴

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

콘크리트 방문자 클래스는 processNode 방법은 노드가 방문 여부를 변경할 수 있는지 여부에 따라 Visitor 또는 ConstVisitor에서 중 상속합니다.

두 방문자간에 코드 중복이 많이 발생하며 const 및 nonconst 노드에 대해서도 다른 탐색 전략을 구현해야하므로이 중복을 피하고 싶습니다. 가능한 한 const_cast을 사용하지 않고 중복 코드를 추출 할 수 있습니까?

답변

11

아래 수행으로 당신은 TVisitor 클래스 템플릿을 정의 할 수 있습니다 :

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

감사합니다. 깨끗한 솔루션. 동료가 템플릿을 너무 많이 싫어하지 않기를 바랍니다. –

+0

@ArneMertz : 좋아, 프로젝트에 행운이 있기를 바랍니다.) –

0

당신은 템플릿을 사용할 수 있습니다 : 클래스 템플릿의 인스턴스화 대응의 형식 별칭으로 VisitorConstVisitor을 사용하여 다음

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

을 그리고 :

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