我正在調查使用訪客模式。我看到的一些示例建議在每個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;
}
這種區別是否正確?也就是說,如果我只打算使用同質容器,我不需要實現接受函數?
謝謝安德魯。另外,在我看到的所有例子中,它們都具有訪問同一Visitor類中多個重載類型的Visit()函數。無論如何,邏輯似乎都需要被複制,爲什麼不使用單個visit()函數創建一個單獨的訪問者? – 2012-01-07 21:43:38
不知道我完全理解你的問題,但每個訪問者對每個元素類型都有一個'visit'重載的原因是,訪問者可以通過調用'visitor-> visit()元素來發現正在操作的元素的具體類型這)'。這是一種以沒有內置支持的語言完成雙重調度的迂迴方式。 – 2012-01-08 01:19:00