C++如何替换这个if ... else语句?

oss*_*cad 3 c++ polymorphism

我有以下C++代码(简化版):

class Shape
{
    bool isCircle = false;
    bool isSquare = false;
}

class Circle : public Shape
{
    // some special members/methods
}

class Square : public Shape
{
    // some special members/methods
}

class CAD
{
    virtual DrawCircle(Circle * circle) = 0;
}

class SWX : public CAD
{
    virtual DrawCircle(Circle * circle){// do some stuff that draws circle on SWX system}
}

class PRO : public CAD
{
    virtual DrawCircle(Circle * circle){// do some stuff that draws circle on PRO system}
}

int main()
{
    Circle * circle = new Circle();
    circle->isCircle = true;

    Square * sq = new Square;
    sq->isSquare = true;

    vector<Shape*> shapes;
    shapes.push_back(circle);
    shapes.push_back(sq);

    SWX * swx = new SWX();

    for( int i = 0 ; i < shapes.size() ; ++i )
    {
        if( shapes[i]->isCircle )
    {
        SWX->DrawCircle((Circle*)(shapes[i]));
    }
    else if( shapes[i]->isSquare )
    {
        SWX->DrawSquare((Square*)(shapes[i]));
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望不再需要if ... else(如果可能的话,在下面所述的限制范围内).

我现在的限制是:

  • CAD和派生类是具有各种外部依赖性的巨大类.
  • CAD类不能与Shape和派生类合并(这本来是理想的,因为我可以使用多态来解决我的问题),因为其他项目/类依赖于Shape类而不能依赖于CAD类.
  • 有十几个Shape派生类和六个CAD衍生类,如果......其他地方正在多个地方发生 - 所以如果任何解决方案很容易理解(更容易说服我的队友改变)会有所帮助遗留代码).

我们非常欢迎您提出任何建议/意见/解决方案.

Lau*_*ves 8

此问题的标准解决方案,特别是考虑到您对依赖关系的限制,是使用访问者模式.

以下是访客模式在您的案例中的工作方式:

  • 你需要一个抽象ShapeVisitor类.它Visit为Shape的每个具体子类都有一个抽象方法.如:Visit(Circle*),Visit(Square*)等等.
  • Shape有一个抽象的AcceptVisitor(ShapeVisitor*)方法.
  • 每个Shape子类都实现AcceptVisitor为只调用visitor->Visit(this)
  • 每个CAD班级都是(或有一个,由你决定)a ShapeVisitor.这些Visit方法针对特定类型进行了适当的绘制Shape.无需条件或铸造.

以下是代码的修改版本,它以极低影响的方式使用访问者模式:

class Circle;
class Square;
class ShapeVisitor
{
    virtual void Visit(Circle *circle) = 0;
    virtual void Visit(Square *square) = 0;
}

class Shape
{
    virtual void AcceptVisitor(ShapeVisitor *visitor) = 0;
}


class Circle : public Shape
{
    // some special members/methods

    virtual void AcceptVisitor(ShapeVisitor *visitor)
    {
        visitor->Visit(this);
    }
}

class Square : public Shape
{
    // some special members/methods

    virtual void AcceptVisitor(ShapeVisitor *visitor)
    {
        visitor->Visit(this);
    }
}

class CAD : public ShapeVisitor
{
    virtual DrawCircle(Circle *circle) = 0;
    virtual DrawSquare(Square *square) = 0;

    virtual void Visit(Circle *circle) {
        DrawCircle(circle);
    }

    virtual void Visit(Square *square) {
        DrawSquare(square);
    }
}

class SWX : public CAD
{
    virtual DrawCircle(Circle *circle){// do some stuff that draws circle on SWX system}

}

class PRO : public CAD
{
    virtual DrawCircle(Circle * circle){// do some stuff that draws circle on PRO system}
}

int main()
{
    Circle * circle = new Circle();
    Square * sq = new Square;

    vector<Shape*> shapes;
    shapes.push_back(circle);
    shapes.push_back(sq);

    SWX * swx = new SWX();

    for( int i = 0 ; i < shapes.size() ; ++i )
    {
        shapes[i]->AcceptVisitor(SWX);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这段代码中,我选择CAD实际上是一个子类ShapeVisitor.此外,由于你已经有了虚拟方法CAD来绘制,我实现了Visit那里的方法(一次),而不是在每个子类中实现一次.一旦你将客户端切换到使用AcceptVisitor而不是直接调用Draw*方法,你可以使这些方法受到保护,然后最终将Visit方法的实现向下移动到子类(即:refactor,以消除由此引起的额外级别的间接有Visit(Foo*)通话DrawFoo(Foo*)).


Jos*_*Lee 6

这是DoubleDispatch的经典案例,您需要为每个可能的(Shape,CAD)对使用单独的方法:

  • Nuke isSquare/ isCirclefields.
  • 添加virtual void DrawOn(CAD*)Shape界面.
  • 实施Circle::DrawOn(CAD*)(例如):

    void Circle::DrawOn(CAD *c) {
      c->DrawCircle(this);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这是"技巧",myCircle->DrawOn(mySWX)无论Shape或CAD的类型如何,都可以调用正确的方法调用.

  • 他提到Shape类不能依赖于CAD类,因为其他类依赖于不应依赖于CAD类的Shape类. (2认同)
  • 啊,我没有注意到这一点.我们可以通过改变形状取决于"绘制事物"界面来狡猾吗? (2认同)