2

根据我目前的需求,我已经实现了访问者模式,我们有一些不同的方面如下:

1>与 GoF 书中说明的经典示例不同,设备的子类没有扁平化。换句话说,子类都在层次结构中。

例如: //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 > 我是否应该关注我标记为“注意”的块,即如果SpecialFloppyDisk调用VisitFloppyDisk而不是SpecialVisitFloppyDisk. 我相信好的代码的设计方式使得它很难出错。但我不确定这种情况是否适用于此。

//////////////////////////////////////////////////////////////////////////
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。它应该是仅包含访问内容的纯类。访问者模式主要用于在不修改这些类的情况下向类族(在本例中为设备)添加新功能。如果添加其他访客 - 那么它很可能对设备价格不感兴趣。如果它对定价感兴趣 - 那么它应该来自PricingVisitor.
  2. 将价格内容移至 PricingVisitor,这是合适的地方。
  3. 不要为不同的Visit方法起不同的名字。编译器会根据类型选择正确的Accept方法*this

Q2:如果 SpecialFloppyDisk 调用 VisitFloppyDisk 而不是 SpecialVisitFloppyDisk 怎么办:

已经在 Q1.3 中提到过 - 不要使用不同的名称 - 这样可以避免问题。

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