首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++如何替换这个if...else语句?

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

Stack Overflow用户
提问于 2010-01-28 06:08:06
回答 8查看 1.1K关注 0票数 3

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

代码语言:javascript
复制
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]));
    }
}

我希望消除对if...else的需求(如果有可能的话,在下面所述的约束范围内)。

我现在的限制是:

  • CAD和派生类是具有各种外部依赖关系的独立类。
  • CAD类不能与形状类和派生类合并(这是理想的,因为那时我可以使用多态性来解决问题),因为其他项目/类依赖于形状类,也不能依赖于CAD类。
  • 有十几个形状派生类和6个CAD派生类,而且这个if...else正在许多地方发生--所以如果任何解决方案都很容易理解(更容易说服我的队友更改遗留代码),这将有所帮助。

欢迎您提出任何建议/意见/解决方案。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2010-01-28 06:18:52

这个问题的标准解决方案,特别是考虑到有关依赖关系的约束,是使用访客模式

下面是访问者模式在您的情况下的工作方式:

  • 您需要一个抽象的ShapeVisitor类。对于每个具体的形状子类,它都有一个抽象的Visit方法。例如:Visit(Circle*)Visit(Square*)等。
  • 形状有一个抽象的AcceptVisitor(ShapeVisitor*)方法。
  • 每个形状子类都将AcceptVisitor实现为调用visitor->Visit(this)
  • 每个CAD类都是一个(或有-a,由您决定)一个ShapeVisitorVisit方法为特定类型的Shape执行适当的绘图。不需要有条件或铸造。

下面是您的代码的修改版本,它以一种非常低影响的方式使用访问者模式:

代码语言:javascript
复制
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);
    }
}

在这段代码中,我选择了让CAD实际上成为ShapeVisitor的子类。另外,由于您已经在CAD中获得了用于绘图的虚拟方法,所以我在那里实现了Visit方法(一次),而不是在每个子类中实现一次。一旦您将客户端切换到使用AcceptVisitor而不是直接调用Visit(Foo*) *方法,您就可以使这些方法受到保护,然后最终将Visit方法的实现转移到子类中(即:重构以删除Visit(Foo*)调用DrawFoo(Foo*)所导致的额外间接)。

票数 8
EN

Stack Overflow用户

发布于 2010-01-28 06:19:44

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

  • isSquare/isCircle字段进行核武器化。
  • virtual void DrawOn(CAD*)添加到Shape接口。
  • 实现Circle::DrawOn(CAD*) (例如): 空圆::DrawOn(CAD *c) {c->Draw循环(此);} 这是一个“技巧”,它允许像myCircle->DrawOn(mySWX)这样的调用调用正确的方法,而不管形状的类型或CAD。
票数 6
EN

Stack Overflow用户

发布于 2010-01-28 06:19:15

您已经有了一些非常不稳定的OO,但是至少DrawXxxx应该成为going ()。然后,圆形、正方形和其他形状将定义一个Draw()方法,该方法为形状上的虚拟绘图方法提供一个实现。然后你只需调用任何形状的绘图,它就会做正确的事情。

isXxxx的布尔人也应该去。类知道它们是什么以及它们的实例可以告诉您(尽管不需要检查何时绘制,因为这将是一个虚拟方法调用)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2152636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档