处理嵌套的if then else /嵌套switch语句

时间:2009-01-30 04:41:30

标签: design-patterns nested

是否有任何设计模式/方法/方法可以删除嵌套if else else condition / switch语句?

我记得在Google代码博客文章中列出了Google人员使用的一些方法。现在似乎无法找到它

7 个答案:

答案 0 :(得分:8)

您是否阅读过{Coding Horror中展平箭头代码的this

如果你使用的是没有例外的语言,你可以用throw或goto替换throw。

答案 1 :(得分:6)

您希望使用使用多态类替换条件的重构。对于example

或者这是另一个example

基本上理想是非常简单的创建对象层次,并将各种行为移动到覆盖方法中。您仍然需要一种方法来创建正确的类,但这可以使用工厂模式完成。

修改

让我补充一点,在每种情况下,这都不是一个完美的解决方案。因为(我忘了你的名字对不起)在我的评论中指出,有时候这可能是一种痛苦,特别是如果你必须创建一个对象模型来做这件事。如果你有这个重构,那么这个重构是非常好的:

function doWork(object x)
{

   if (x is a type of Apple)
   {
      x.Eat();

   } else if (x is a type of Orange)
   {
      x.Peel();
      x.Eat();
   }

}

在这里,您可以将切换重构为每个水果将处理的新方法。

修改

正如有人指出你如何创建正确的类型进入doWork,有更多的方法可以解决这个问题,然后我可以列举一些基本的方法。第一个也是最直接的(是的,与这个问题相反)是一个开关:

class FruitFactory
{
   Fruit GetMeMoreFruit(typeOfFruit)
   {
         switch (typeOfFruit)
         ...
         ...
   }
}

这种方法的优点是它易于编写,通常是我使用的第一种方法。虽然你仍然有一个switch语句,它被隔离到一个代码区域并且非常基本,它返回的是一个n对象。如果你只有几个对象和它们;不改变它的效果非常好。

您可以查看的其他更多强制模式是Abstract Factory。如果您的平台支持,您也可以动态创建Fruit。您也可以使用类似Provider Pattern的内容。这对我来说意味着你配置你的对象然后你有一个工厂,它基于配置和你给工厂的密钥动态创建正确的类。

答案 2 :(得分:3)

我实际上在2008年4月写了关于如何在我的博客中解决这个问题。看看here并告诉我你的想法。

我建议你:

  1. 使用多态来获得所需的正确运行时行为,而无需条件语句。

  2. 获取所有条件语句,并将它们移动到某种“工厂”中,该工厂将在运行时向您提供适当的类型。

  3. 你已经完成了。那不容易吗? :)

  4. 如果您想查看有关如何转换代码的实际代码示例,请访问我的博客。

    P.S。这不是一种廉价的自我推销尝试;我已经很长时间以来一直是SO用户,这是我第一次链接到我的博客 - 而且我之所以这样做是因为我认为它是相关的。

答案 3 :(得分:2)

您是否在考虑Google的“The Clean Code Talks -- Inheritance, Polymorphism, & Testing”视频?它讨论了使用面向对象技术来删除if / switch条件的方法。

答案 4 :(得分:1)

您没有说出您正在使用的语言,但如果您使用的是OO语言,例如C ++,C#或Java,您通常可以使用虚函数来解决同样的问题。您目前正在使用switch语句以更可扩展的方式进行求解。在C ++的情况下,比较:

class X {
public:
    int get_type();     /* Or an enum return type or similar */
    ...
};

void eat(X& x) {
    switch (x.get_type()) {
    TYPE_A: eat_A(x); break;
    TYPE_B: eat_B(x); break;
    TYPE_C: eat_C(x); break;
    }
}

void drink(X& x) {
    switch (x.get_type()) {
    TYPE_A: drink_A(x); break;
    TYPE_B: drink_B(x); break;
    TYPE_C: drink_C(x); break;
    }
}

void be_merry(X& x) {
    switch (x.get_type()) {
    TYPE_A: be_merry_A(x); break;
    TYPE_B: be_merry_B(x); break;
    TYPE_C: be_merry_C(x); break;
    }
}

class Base {
    virtual void eat() = 0;
    virtual void drink() = 0;
    virtual void be_merry() = 0;
    ...
};

class A : public Base {
public:
    virtual void eat() { /* Eat A-specific stuff */ }
    virtual void drink() { /* Drink A-specific stuff */ }
    virtual void be_merry() { /* Be merry in an A-specific way */ }
};

class B : public Base {
public:
    virtual void eat() { /* Eat B-specific stuff */ }
    virtual void drink() { /* Drink B-specific stuff */ }
    virtual void be_merry() { /* Be merry in an B-specific way */ }
};

class C : public Base {
public:
    virtual void eat() { /* Eat C-specific stuff */ }
    virtual void drink() { /* Drink C-specific stuff */ }
    virtual void be_merry() { /* Be merry in a C-specific way */ }
};

优点是您可以添加新的Base - 派生类DEF等,而无需触及任何仅处理指针的代码或Base的引用,因此没有任何内容可以像switch语句在原始解决方案中那样过时。 (在Java中,转换看起来非常相似,默认情况下方法是虚拟的,我确信它在C#中看起来也很相似。)在大型项目中,这是巨大的可维护性获胜。

答案 5 :(得分:1)

您可能希望查看Strategy Pattern,其中不是将一长串ifs与链接条件放在一起,而是将每个条件抽象为另一个对象,每个对象定义其特定行为。

定义这些对象的类将实现一个将由父对象调用的接口。

答案 6 :(得分:0)

怎么样:

/* Code Block 1... */

if(/* result of some condition or function call */)
{
   /* Code Block 2... */

   if(/* result of some condition or function call */)
   {
      /* Code Block 3... */

      if(/* result of some condition or function call */)
      {
         /* Code Block 4... */
      }
   }
}

成为这个:

/* Code Block 1... */
IsOk = /* result of some condition or function call */

if(IsOK)
{
   /* Code Block 2... */
   IsOk = /* result of some condition or function call */
}

if(IsOK)
{
   /* Code Block 3...*/
   IsOk = /* result of some condition or function call */
}

if(IsOK)
{
   /* Code Block 4...*/
   IsOk = /* result of some condition or function call */
}

/* And so on... */

如果IsOk在适当的时候变为假,你当然可以返回。