Visitorパターンの使用を検討しています。いくつかの例では、すべてのElementサブクラスでaccept(Visitor)関数を使用することを推奨しています。その関数のアイデアは、訪問者が多態型を含むコレクションを訪問できるようにすることですか?このコードでは、訪問者は2種類の蓄積を行い、accept()は必要ありません。このコードでVisitorパターンでの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()関数で別の訪問者を作るのはどうですか? –
私はあなたの質問を完全に理解していますが、各訪問者がそれぞれの要素タイプに対して 'visit'オーバーロードを持っている理由は、訪問者が' visitor-> visitという要素を呼び出すことによって、これ) '。これは、組み込みのサポートがない言語での二重ディスパッチを実現するラウンドアバウトの方法です。 –