2

私の現在の要件に基づいて、訪問者パターンを実装しました。次のように、いくつかの異なる側面があります。

1>GoF 本で説明されている古典的な例とは異なり、Equipment のサブクラスは平坦化されていません。つまり、サブクラスはすべて階層内にあります。

例: //Flat EquipmentA : public Equipment {} EquipmentB : public Equipment {} EquipmentC : public Equipment {}

//hierarchy
EquipmentA : public Equipment {}
EquipmentB : public EquipmentA {}
EquipmentC : public EquipmentB {}

2>サブクラスには、ベースで定義された仮想関数ではない特殊な関数がいくつかあります。例えば:

`EquipmentA` may define a function called `GetFactorRate`
`EquipmentB` may define a function called `GetAmplifyRate`

これらすべてを念頭に置いてください。これが私のコードです。

質問 1 > コードに問題はありますか?

質問 2 > 「メモ」としてマークしたブロック、つまりの代わりにwhat ifSpecialFloppyDiskを呼び出す必要があります。私は、良いコードは間違いを犯しにくいように設計されていると信じています。しかし、このケースがここに当てはまるかどうかはわかりません。VisitFloppyDiskSpecialVisitFloppyDisk

//////////////////////////////////////////////////////////////////////////
class FloppyDisk;
class SpecialFloppyDisk;
class EquipmentVisitor
{
public:
    virtual ~EquipmentVisitor() {}    
    // modify Equipment based on different subclass of Equipment
    virtual void VisitFloppyDisk(FloppyDisk&) = 0;
    virtual void VisitSpecialFloppyDisk(SpecialFloppyDisk&) = 0;

    int GetTotalPrice() const { return m_iTotalPrice; }
protected:
    int m_iTotalPrice;    
protected:
    EquipmentVisitor() {}
};    
//////////////////////////////////////////////////////////////////////////
class Equipment {
public:
    virtual ~Equipment() {}    
    // return the price of the Equipment
    virtual int GetPrice() const = 0;

    virtual void Accept(EquipmentVisitor&) = 0;
protected:
    Equipment() {}
};
//////////////////////////////////////////////////////////////////////////
class FloppyDisk : public Equipment
{
public:
    // return the price of the Equipment
    virtual int GetPrice() const {return 100;}
    int GetFactorRate() const {return 2; } // x 2

    virtual void Accept(EquipmentVisitor& e){e.VisitFloppyDisk(*this);}
};
//////////////////////////////////////////////////////////////////////////
class SpecialFloppyDisk : public FloppyDisk
{
public:
    virtual std::string GetName() const {return std::string("Bus");}            
    // return the price of the Equipment
    virtual int GetPrice() const {return 20000;}

    int GetAmplifyRate() const {return 11; }// x 11
    virtual void Accept(EquipmentVisitor& e)
    {
        e.VisitSpecialFloppyDisk(*this);
        // Note: if called the following function by accident, then it introduces
        // hidden bugs!!!!
        // e.VisitFloppyDisk(*this);
    }
};
//////////////////////////////////////////////////////////////////////////
class PricingVisitor : public EquipmentVisitor
{
public:
    virtual void VisitFloppyDisk(FloppyDisk& e)
    {m_iTotalPrice = e.GetPrice() * e.GetFactorRate();}
    virtual void VisitSpecialFloppyDisk(SpecialFloppyDisk& e)
    {   m_iTotalPrice = e.GetPrice() * e.GetAmplifyRate(); }
};
//////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
    PricingVisitor pricingVisitor;
    SpecialFloppyDisk specialFloppyDisk;
    FloppyDisk floppyDisk;

    floppyDisk.Accept(pricingVisitor);
    // output: pricingVisitor.GetTotalPrice(): 200
    // i.e. 100 x 2
    std::cout << "pricingVisitor.GetTotalPrice(): " << pricingVisitor.GetTotalPrice() << std::endl;

    // output: pricingVisitor.GetTotalPrice(): 220000
    // i.e. 20000 x 11
    specialFloppyDisk.Accept(pricingVisitor);
    std::cout << "pricingVisitor.GetTotalPrice(): " << pricingVisitor.GetTotalPrice() << std::endl;

    return 0;
}
4

1 に答える 1

0

Q1: 問題はありますか? はい、そうです。設計上の問題:

  1. EquipmentVisitor持ってはならない GetTotalPrice()/m_iTotalPrice。これは、Visit のみを含む純粋なクラスである必要があります。ビジター パターンは主に、これらのクラスを変更せずにクラス ファミリ (この場合は Equipment) に新しい機能を追加するためのものです。他の訪問者を追加する場合、おそらく、機器の価格には関心がありません。価格設定に関心がある場合は、 から派生する必要がありますPricingVisitor
  2. 価格の要素を PricingVisitor に移動します。これは適切な場所です。
  3. Visitメソッドごとに異なる名前を付けないでください。コンパイラは、型にAccept基づいて適切な方法を選択し*thisます。

Q2: SpecialFloppyDisk が SpecialVisitFloppyDisk の代わりに VisitFloppyDisk を呼び出す場合:

Q1.3 で既に言及されています - 別の名前を使用しないでください - これにより、問題を回避できます。

class EquipmentVisitor
{
public:
   virtual ~EquipmentVisitor() {}    
   virtual void Visit(FloppyDisk&) = 0;
   virtual void Visit(SpecialFloppyDisk&) = 0;
};  
于 2012-08-02T22:26:44.913 に答える