代码之家  ›  专栏  ›  技术社区  ›  Cherian

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

  •  11
  • Cherian  · 技术社区  · 16 年前

    是否有任何设计模式/方法/方法来删除嵌套的if-then-else条件/开关语句?

    我记得在一篇谷歌代码博客文章中,我遇到了一些谷歌人使用的方法。但我现在似乎找不到

    7 回复  |  直到 16 年前
        1
  •  8
  •   Mark    16 年前

    你读过吗 this 从编码恐怖中展平箭头代码?

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

        2
  •  6
  •   JoshBerke    16 年前

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

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

    编辑

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

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

    您可以研究的其他更复杂的模式是 Abstract Factory . 如果您的平台支持,您还可以动态创建水果。您也可以使用类似 Provider Pattern

        3
  •  3
  •   Esteban Araya    16 年前

    事实上,我在2008年4月的博客中写到了如何解决这个问题。看一看 here 让我知道你的想法。

    我建议你:

    1. 使用多态性可以在不使用条件语句的情况下获得所需的正确运行时行为。

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

    3. 你完了。那不是很容易吗?:)

    如果你想看到一些关于如何转换代码的实际代码示例,请访问我的博客。

    顺便说一句,这不是一次廉价的自我推销尝试;我已经是一个很长时间的用户了,这是我第一次链接到我的博客——我这么做只是因为我认为这是相关的。

        4
  •  2
  •   Zach Scrivena    16 年前

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

        5
  •  1
  •   Jon Limjap    16 年前

    Strategy Pattern ,其中,不是放置带有链接条件的长ifs链,而是将每个条件抽象为不同的对象,每个对象定义其特定行为。

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

        6
  •  1
  •   j_random_hacker    16 年前

    你不说你使用的是什么语言,但是如果你使用的是一种面向对象语言,比如C++、C语言或java,你就可以经常使用。 虚拟函数 解决与您当前正在使用解决的问题相同的问题 switch

    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 D E , F 语句可以在原始解决方案中使用。(这种转换在Java中看起来非常相似,默认情况下方法是虚拟的,我相信在C#中也很相似。)在一个大型项目中,这是一个 我们赢了。

        7
  •  0
  •   Steve Melnikoff    16 年前

    怎么样:

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