2012-01-07 50 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; 
}; 

?它有助於在單個訪客類中有多重過載嗎?還是它只是引入不必要的依賴關係?