2012-01-07 6 views
3

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; 
} 

が正しいこの違いますか?つまり、均質なコンテナを持つことだけを考えている場合、私は受け入れ関数を実装する必要はありませんか?

答えて

1

この区別は正しいですか?つまり、私は受け入れる機能を実装する必要はありません均質な容器 を持つことを計画している場合ですか?

はい、それがパターンの本質です。

基本的に、比較的安定したElement階層をお持ちの場合は、必要に応じて新しいVisitor派生語を追加することができます。訪問者は、操作されている要素の具体的なタイプを知っている呼び出し者なしで呼び出すことができます。私が言っている何

+0

ありがとうアンドリュー。また、私が見たすべての例では、同じVisitorクラス内で複数のオーバーロードされた型のVisit()関数があります。とにかくロジックを複製する必要があるようです。なぜなら、単一のvisit()関数で別の訪問者を作るのはどうですか? –

+0

私はあなたの質問を完全に理解していますが、各訪問者がそれぞれの要素タイプに対して 'visit'オーバーロードを持っている理由は、訪問者が' visitor-> visitという要素を呼び出すことによって、これ) '。これは、組み込みのサポートがない言語での二重ディスパッチを実現するラウンドアバウトの方法です。 –

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; 
}; 

? 1人のビジタークラスで複数のオーバーロードを行うのに役立ちますか?それとも不必要な依存関係を導入するだけですか?

関連する問題