2012-01-07 46 views
3

我正在调查使用访客模式。我看到的一些示例建议在每个Element子类中使用accept(Visitor)函数。这个函数的思想只是为了让访问者可以访问包含多态类型的集合吗?在这段代码中,我使用访问者进行两种类型的累计,并且它不需要accept()。访客模式中使用accept()

#include <iostream> 
#include <vector> 

class IntItem 
{ 
public: 
    IntItem(const int a) : IntData(a){} 

    int IntData; 
}; 

class DoubleItem 
{ 
public: 
    DoubleItem(const double a) : DoubleData(a){} 

    double DoubleData; 
}; 

class Visitor 
{ 
public: 
    virtual void Visit(IntItem &item) = 0; 
    virtual void Visit(DoubleItem &item) = 0; 
}; 


class SumAccumulator : public Visitor 
{ 
public: 

    SumAccumulator() : Sum(0) {} 
    void Visit(IntItem &item) 
    { 
    Sum += item.IntData; 
    } 

    void Visit(DoubleItem &item) 
    { 
    Sum += item.DoubleData; 
    } 

    double Sum; 
}; 

class AverageAccumulator : public Visitor 
{ 
public: 

    AverageAccumulator() : Average(0), Counter(0) {} 
    void Visit(IntItem &item) 
    { 
    Counter++; 
    Average = (Counter - 1) * Average + item.IntData; 
    Average /= Counter; 
    } 

    void Visit(DoubleItem &item) 
    { 
    Counter++; 
    Average = (Counter - 1) * Average + item.DoubleData; 
    Average /= Counter; 
    } 

    int Counter; 
    double Average; 
}; 

class IntCollection 
{ 
public: 
    void Visit(Visitor &visitor) 
    { 
    for(unsigned int i = 0; i < IntItems.size(); ++i) 
     { 
     visitor.Visit(IntItems[i]); 
     } 
    } 

    void AddIntItem(const IntItem& item) 
    { 
    IntItems.push_back(item); 
    } 

private: 
    std::vector<IntItem> IntItems; 

}; 

class DoubleCollection 
{ 
public: 
    void Visit(Visitor &visitor) 
    { 
    for(unsigned int i = 0; i < DoubleItems.size(); ++i) 
     { 
     visitor.Visit(DoubleItems[i]); 
     } 
    } 

    void AddDoubleItem(const DoubleItem& item) 
    { 
    DoubleItems.push_back(item); 
    } 

private: 
    std::vector<DoubleItem> DoubleItems; 
}; 

int main(int argc, char *argv[]) 
{ 
    /////// Ints //////// 
    IntCollection intCollection; 
    for(unsigned int i = 0; i < 4; ++i) 
    { 
    intCollection.AddIntItem(IntItem(i)); 
    } 

    SumAccumulator intSumAccumulator; 
    intCollection.Visit(intSumAccumulator); 
    std::cout << "int sum: " << intSumAccumulator.Sum << std::endl; 

    AverageAccumulator intAverageAccumulator; 
    intCollection.Visit(intAverageAccumulator); 
    std::cout << "int average: " << intAverageAccumulator.Average << std::endl; 

    /////// Doubles //////// 
    DoubleCollection doubleCollection; 
    for(unsigned int i = 0; i < 4; ++i) 
    { 
    doubleCollection.AddDoubleItem(DoubleItem(static_cast<double>(i) + .1)); 
    } 
    SumAccumulator doubleSumAccumulator; 
    doubleCollection.Visit(doubleSumAccumulator); 
    std::cout << "double sum: " << doubleSumAccumulator.Sum << std::endl; 

    AverageAccumulator doubleAverageAccumulator; 
    doubleCollection.Visit(doubleAverageAccumulator); 
    std::cout << "double average: " << doubleAverageAccumulator.Average << std::endl; 

    return 0; 
} 

在这段代码中,我使用接受(),唯一不同的是,容器可以包含在同一容器中不同类型的对象:

#include <iostream> 
#include <string> 
#include <vector> 

class IntElement; 
class DoubleElement; 

class Visitor 
{ 
public: 
    virtual void visit(IntElement *e) = 0; 
    virtual void visit(DoubleElement *e) = 0; 
}; 

class Element 
{ 
public: 
    virtual void accept(class Visitor &v) = 0; 
}; 

class IntElement: public Element 
{ 
public: 
    IntElement(int i) : IntData(i){} 
    /*virtual*/void accept(Visitor &v) 
    { 
    v.visit(this); 
    } 

    int IntData; 
}; 

class DoubleElement: public Element 
{ 
public: 
    DoubleElement(double d) : DoubleData(d){} 
    /*virtual*/void accept(Visitor &v) 
    { 
    v.visit(this); 
    } 

    double DoubleData; 
}; 

class SumVisitor: public Visitor 
{ 
public: 
    SumVisitor() : Sum(0){} 
    /*virtual*/void visit(IntElement *e) 
    { 
    Sum += e->IntData; 
    } 
    /*virtual*/void visit(DoubleElement *e) 
    { 
    Sum += e->DoubleData; 
    } 

    double Sum; 
}; 

class AverageVisitor: public Visitor 
{ 
public: 
    AverageVisitor() : Counter(0) , Average(0){} 
    /*virtual*/void visit(IntElement *e) 
    { 
    Counter++; 
    Average = (Counter - 1) * Average + e->IntData; 
    Average /= Counter; 
    } 
    /*virtual*/void visit(DoubleElement *e) 
    { 
    Counter++; 
    Average = (Counter - 1) * Average + e->DoubleData; 
    Average /= Counter; 
    } 
    double Average; 
    int Counter; 
}; 

int main() 
{ 
    std::vector<Element*> elements; 
    elements.push_back(new IntElement(0)); 
    elements.push_back(new IntElement(1)); 
    elements.push_back(new DoubleElement(2)); 
    elements.push_back(new DoubleElement(3)); 

    SumVisitor sumVisitor; 
    AverageVisitor averageVisitor; 
    for (int i = 0; i < elements.size(); i++) 
    { 
    elements[i]->accept(sumVisitor); 
    elements[i]->accept(averageVisitor); 
    } 
    std::cout << "sum: " << sumVisitor.Sum << std::endl; 
    std::cout << "average: " << averageVisitor.Average << std::endl; 
} 

这种区别是否正确?也就是说,如果我只打算使用同质容器,我不需要实现接受函数?

回答

1

这种区分是否正确?也就是说,如果我只打算拥有同质容器,我不需要实现接受函数?

是的,这是模式的本质。

基本上,如果您有一个相对稳定的Element层次结构,它允许您根据需要添加新的Visitor衍生物。然后可以调用访问者,而无需调用者知道正在操作的元素的具体类型。

+0

谢谢安德鲁。另外,在我看到的所有例子中,它们都具有访问同一Visitor类中多个重载类型的Visit()函数。无论如何,逻辑似乎都需要被复制,为什么不使用单个visit()函数创建一个单独的访问者? – 2012-01-07 21:43:38

+0

不知道我完全理解你的问题,但每个访问者对每个元素类型都有一个'visit'重载的原因是,访问者可以通过调用'visitor-> visit()元素来发现正在操作的元素的具体类型这)'。这是一种以没有内置支持的语言完成双重调度的迂回方式。 – 2012-01-08 01:19:00

0

我说的是不是:

class SumVisitor: public Visitor 
{ 
public: 
    SumVisitor() : Sum(0){} 
    /*virtual*/void visit(IntElement *e) 
    { 
    Sum += e->IntData; 
    } 
    /*virtual*/void visit(DoubleElement *e) 
    { 
    Sum += e->DoubleData; 
    } 

    double Sum; 
}; 

为什么不能有:

class IntSumVisitor: public Visitor 
{ 
public: 
    SumVisitor() : Sum(0){} 
    /*virtual*/void visit(IntElement *e) 
    { 
    Sum += e->IntData; 
    } 

    double Sum; 
}; 

class DoubleSumVisitor: public Visitor 
{ 
public: 
    DoubleSumVisitor() : Sum(0){} 
    /*virtual*/void visit(IntElement *e) 
    { 
    Sum += e->IntData; 
    } 

    int Sum; 
}; 

?它有助于在单个访客类中有多重过载吗?还是它只是引入不必要的依赖关系?