C++ 与访问者设计模式实现相关的问题

C++ 与访问者设计模式实现相关的问题,c++,design-patterns,visitor-pattern,C++,Design Patterns,Visitor Pattern,根据我当前的需求,我已经实现了访客模式,我们有以下几个不同方面: 1> 与GoF手册中的经典示例不同,设备的子类不是扁平的。换句话说,子类都在层次结构中 例如: //平坦的 设备A:公共设备{} 设备B:公共设备{} 设备C:公共设备{} //hierarchy EquipmentA : public Equipment {} EquipmentB : public EquipmentA {} EquipmentC : public EquipmentB {} 2> 子类有一些特殊的函数,这些

根据我当前的需求,我已经实现了访客模式,我们有以下几个不同方面:

1> 与GoF手册中的经典示例不同,设备的子类不是扁平的。换句话说,子类都在层次结构中

例如: //平坦的 设备A:公共设备{} 设备B:公共设备{} 设备C:公共设备{}

//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>我应该关注我标记为“备注”的区块吗 i、 e.如果
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;
}
//////////////////////////////////////////////////////////////////////////
类软盘;
类SpecialFloppyDisk;
班级设备访客
{
公众:
虚拟~EquipmentVisitor(){}
//根据设备的不同子类修改设备
虚拟无效VisitFloppyDisk(FloppyDisk&)=0;
虚拟无效访问SpecialFloppyDisk(SpecialFloppyDisk&)=0;
int GetTotalPrice()常量{return m_iTotalPrice;}
受保护的:
国际电信价格;
受保护的:
设备访问者(){}
};    
//////////////////////////////////////////////////////////////////////////
一流设备{
公众:
虚拟~Equipment(){}
//退还设备的价格
虚拟整数GetPrice()常量=0;
虚拟无效接受(设备访问者&)=0;
受保护的:
设备(){}
};
//////////////////////////////////////////////////////////////////////////
磁盘类:公共设备
{
公众:
//退还设备的价格
虚拟int GetPrice()常量{return 100;}
int GetFactorRate()常量{return 2;}//x 2
虚拟无效接受(设备访问者&e){e.VisitFloppyDisk(*this);}
};
//////////////////////////////////////////////////////////////////////////
类SpecialFloppyDisk:公共FloppyDisk
{
公众:
虚拟std::string GetName()常量{返回std::string(“总线”);}
//退还设备的价格
虚拟int GetPrice()常量{return 20000;}
int getAmplicateRate()常量{return 11;}//x 11
虚拟无效接受(设备访客和设备)
{
e、 访问SpecialFloppyDisk(*此项);
//注意:如果意外调用以下函数,那么它将引入
//隐藏的虫子!!!!
//e.VisitFloppyDisk(*本文件);
}
};
//////////////////////////////////////////////////////////////////////////
类PricingVisitor:公共设备访客
{
公众:
虚拟无效访问FloppyDisk(FloppyDisk&e)
{m_iTotalPrice=e.GetPrice()*e.GetFactorRate();}
虚拟无效访问专用FloppyDisk(专用FloppyDisk&e)
{m_iTotalPrice=e.GetPrice()*e.GetRate();}
};
//////////////////////////////////////////////////////////////////////////
int _tmain(int argc,_TCHAR*argv[]
{
PricingVisitor PricingVisitor;
SpecialFloppyDisk SpecialFloppyDisk;
FloppyDisk-FloppyDisk;
接受(pricingVisitor);
//输出:pricingVisitor.GetTotalPrice():200
//即100 x 2

std::coutQ1:有问题吗?有。设计问题:

  • EquipmentVisitor
    不应具有
    GetTotalPrice()/m_iTotalPrice
    。它应该是纯类,仅包含访问内容。Visitor模式主要用于向类族(在本例中为设备)添加新功能不修改这些类。如果添加其他访问者-那么它很可能对设备价格不感兴趣。如果它对定价感兴趣-那么它应该派生自
    PricingVisitor
  • 把价格的东西移到PricingVisitor,这是合适的地方
  • 不要为不同的
    访问
    方法指定不同的名称。编译器将根据
    *此
    类型在
    接受
    中选择正确的方法
  • Q2:如果SpecialFloppyDisk调用VisitFloppyDisk而不是SpecialVisitFloppyDisk怎么办:

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

    class EquipmentVisitor
    {
    public:
       virtual ~EquipmentVisitor() {}    
       virtual void Visit(FloppyDisk&) = 0;
       virtual void Visit(SpecialFloppyDisk&) = 0;
    };  
    

    Q1:有问题吗?有。设计问题:

  • EquipmentVisitor
    不应具有
    GetTotalPrice()/m_iTotalPrice
    。它应该是纯类,仅包含访问内容。Visitor模式主要用于向类族(在本例中为设备)添加新功能不修改这些类。如果添加其他访问者-那么它很可能对设备价格不感兴趣。如果它对定价感兴趣-那么它应该派生自
    PricingVisitor
  • 把价格的东西移到PricingVisitor,这是合适的地方
  • 不要为不同的
    访问
    方法指定不同的名称。编译器将根据
    *此
    类型在
    接受
    中选择正确的方法
  • Q2:如果SpecialFloppyDisk调用VisitFloppyDisk而不是SpecialVisitFloppyDisk怎么办:

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

    class EquipmentVisitor
    {
    public:
       virtual ~EquipmentVisitor() {}    
       virtual void Visit(FloppyDisk&) = 0;
       virtual void Visit(SpecialFloppyDisk&) = 0;
    };  
    

    这可能是在代码审查上,那是很多代码。这可能是在代码审查上,那是很多代码。