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

时间:2022-10-28 22:09:47

Are there any design patterns/methods/ways to remove nested if then else conditions/switch statements?

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

I remember coming across some methods used by the Google folks listed in a Google code blog post. Can’t seem to find it now though

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

7 个解决方案

#1


You want to use a refactoring that replaces a conditional using a polymorphic class. For example.

您希望使用使用多态类替换条件的重构。例如。

Or here's another example

或者这是另一个例子

Essentially the ideal is very simple you create an object heirarchy, and move the various behaviors into an overriden method. You will still need a method to create the right class but this can be done using a factory pattern.

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

Edit

Let me add that this is not a perfect solution in every case. As (I forgot your name sorry) pointed in my comments, some times this can be a pain especially if you have to create an object model just to do this. This refactoring excells if you have this:

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

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();
   }

}

Here you can refactor the switch into some new method that each fruit will handle.

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

Edit

As someone pointed out how do you create the right type to go into doWork, there are more ways to solve this problem then I could probally list so some basic ways. The first and most straight forward (and yes goes against the grain of this question) is a switch:

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

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

The nice thing about this approach is it's easy to write, and is usually the first method I use. While you still have a switch statement its isolated to one area of code and is very basic all it returns is a n object. If you only have a couple of objects and they;re not changing this works very well.

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

Other more compelx patterns you can look into is an Abstract Factory. You could also dynamically create the Fruit if your platform supports it. You could also use something like the Provider Pattern. Which essentially to me means you configure your object and then you have a factory which based on the configuration and a key you give the factory creates the right class dynamically.

您可以研究的其他更多compelx模式是抽象工厂。如果您的平台支持,您还可以动态创建Fruit。您还可以使用提供者模式之类的东西。这对我来说意味着你配置你的对象,然后你有一个工厂,它基于配置和你给工厂的密钥动态创建正确的类。

#2


Have you read this on flattening arrow code from Coding Horror?

你有没有在Coding Horror上展平箭头代码时看到这个?

You can replace throw with return or goto if you're using a language without exceptions.

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

#3


I actually wrote about how to solve this issues in my blog in April of 2008. Take a look here and let me know what you think.

我实际上在2008年4月写了一篇关于如何在我的博客中解决这个问题的文章。看看这里,让我知道你的想法。

I recommend you:

我推荐你:

  1. Use polymorphism to get the correct run-time behavior you need without conditional statements.

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

  2. Take all your conditional statements, and move them into some sort of "factory" which will hand you the appropriate type at run-time.

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

  3. You're done. Wasn't that easy? :)

    你完成了。那不容易吗? :)

If you want to see some actual code sample on how transform your code, head over to my blog.

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

P.S. This is not a cheap attempt at self promotion; I've been a SO user for a long time now, and this is the first time I've linked to my blog - and I've only done so because I think it's relevant.

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

#4


Were you thinking of Google's "The Clean Code Talks -- Inheritance, Polymorphism, & Testing" video? It discusses approaches to using Object Oriented techniques to remove if/switch conditionals.

您是否在考虑Google的“清洁代码会谈 - 继承,多态,和测试”视频?它讨论了使用面向对象技术来删除if / switch条件的方法。

#5


You might want to look at the Strategy Pattern, wherein instead of putting a long chain of ifs with linked conditions, you abstract each condition to a different object, each one defining what its specific behavior.

您可能希望查看策略模式,其中不是将具有链接条件的长链ifs放在一起,而是将每个条件抽象为不同的对象,每个对象定义其特定行为。

The class that defines those objects will implement an Interface which will be called by the parent object.

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

#6


You don't say what language you're using, but if you are using an OO language such as C++, C# or Java, you can often use virtual functions to solve the same problem as you are currently solving with a switch statement, and in a more extensible way. In the case of C++, compare:

您没有说出您正在使用的语言,但如果您使用的是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;
    }
}

with

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 */ }
};

The advantage is that you can add new Base-derived classes D, E, F and so on without having to touch any code that only deals with pointers or references to Base, so there is nothing that can get out of date the way that a switch statement can in the original solution. (The transformation looks very similar in Java, where methods are virtual by default, and I'm sure it looks similar in C# too.) On a large project, this is a huge maintainability win.

优点是你可以添加新的Base派生类D,E,F等,而不必触及任何只处理指针或Base的引用的代码,所以没有任何东西可以像a一样过时了。 switch语句可以在原始解决方案中。 (在Java中,转换看起来非常相似,默认情况下方法是虚拟的,我确信它在C#中看起来也很相似。)在大型项目中,这是一个巨大的可维护性胜利。

#7


How about:

/* 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... */
      }
   }
}

Becomes this:

/* 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... */

You can of course return if ever IsOk becomes false, if appropriate.

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

#1


You want to use a refactoring that replaces a conditional using a polymorphic class. For example.

您希望使用使用多态类替换条件的重构。例如。

Or here's another example

或者这是另一个例子

Essentially the ideal is very simple you create an object heirarchy, and move the various behaviors into an overriden method. You will still need a method to create the right class but this can be done using a factory pattern.

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

Edit

Let me add that this is not a perfect solution in every case. As (I forgot your name sorry) pointed in my comments, some times this can be a pain especially if you have to create an object model just to do this. This refactoring excells if you have this:

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

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();
   }

}

Here you can refactor the switch into some new method that each fruit will handle.

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

Edit

As someone pointed out how do you create the right type to go into doWork, there are more ways to solve this problem then I could probally list so some basic ways. The first and most straight forward (and yes goes against the grain of this question) is a switch:

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

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

The nice thing about this approach is it's easy to write, and is usually the first method I use. While you still have a switch statement its isolated to one area of code and is very basic all it returns is a n object. If you only have a couple of objects and they;re not changing this works very well.

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

Other more compelx patterns you can look into is an Abstract Factory. You could also dynamically create the Fruit if your platform supports it. You could also use something like the Provider Pattern. Which essentially to me means you configure your object and then you have a factory which based on the configuration and a key you give the factory creates the right class dynamically.

您可以研究的其他更多compelx模式是抽象工厂。如果您的平台支持,您还可以动态创建Fruit。您还可以使用提供者模式之类的东西。这对我来说意味着你配置你的对象,然后你有一个工厂,它基于配置和你给工厂的密钥动态创建正确的类。

#2


Have you read this on flattening arrow code from Coding Horror?

你有没有在Coding Horror上展平箭头代码时看到这个?

You can replace throw with return or goto if you're using a language without exceptions.

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

#3


I actually wrote about how to solve this issues in my blog in April of 2008. Take a look here and let me know what you think.

我实际上在2008年4月写了一篇关于如何在我的博客中解决这个问题的文章。看看这里,让我知道你的想法。

I recommend you:

我推荐你:

  1. Use polymorphism to get the correct run-time behavior you need without conditional statements.

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

  2. Take all your conditional statements, and move them into some sort of "factory" which will hand you the appropriate type at run-time.

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

  3. You're done. Wasn't that easy? :)

    你完成了。那不容易吗? :)

If you want to see some actual code sample on how transform your code, head over to my blog.

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

P.S. This is not a cheap attempt at self promotion; I've been a SO user for a long time now, and this is the first time I've linked to my blog - and I've only done so because I think it's relevant.

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

#4


Were you thinking of Google's "The Clean Code Talks -- Inheritance, Polymorphism, & Testing" video? It discusses approaches to using Object Oriented techniques to remove if/switch conditionals.

您是否在考虑Google的“清洁代码会谈 - 继承,多态,和测试”视频?它讨论了使用面向对象技术来删除if / switch条件的方法。

#5


You might want to look at the Strategy Pattern, wherein instead of putting a long chain of ifs with linked conditions, you abstract each condition to a different object, each one defining what its specific behavior.

您可能希望查看策略模式,其中不是将具有链接条件的长链ifs放在一起,而是将每个条件抽象为不同的对象,每个对象定义其特定行为。

The class that defines those objects will implement an Interface which will be called by the parent object.

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

#6


You don't say what language you're using, but if you are using an OO language such as C++, C# or Java, you can often use virtual functions to solve the same problem as you are currently solving with a switch statement, and in a more extensible way. In the case of C++, compare:

您没有说出您正在使用的语言,但如果您使用的是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;
    }
}

with

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 */ }
};

The advantage is that you can add new Base-derived classes D, E, F and so on without having to touch any code that only deals with pointers or references to Base, so there is nothing that can get out of date the way that a switch statement can in the original solution. (The transformation looks very similar in Java, where methods are virtual by default, and I'm sure it looks similar in C# too.) On a large project, this is a huge maintainability win.

优点是你可以添加新的Base派生类D,E,F等,而不必触及任何只处理指针或Base的引用的代码,所以没有任何东西可以像a一样过时了。 switch语句可以在原始解决方案中。 (在Java中,转换看起来非常相似,默认情况下方法是虚拟的,我确信它在C#中看起来也很相似。)在大型项目中,这是一个巨大的可维护性胜利。

#7


How about:

/* 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... */
      }
   }
}

Becomes this:

/* 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... */

You can of course return if ever IsOk becomes false, if appropriate.

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