我正在调查使用访客模式。我看到的一些示例建议在每个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