重构if-else-if结构

时间:2013-09-18 16:32:22

标签: c++ c++11 refactoring

如何重构以下C ++代码?我在我的程序中使用C ++ 11

void f(int a, int b, int c, int d, int e, int f) {

  // MAX1..MAX6 are constants, N1..N6 are constants
    if( a > MAX1) {
        .. code block 1..
    }
    else if(b > MAX2) {
        .. code block 2..
    }
    else if(c > MAX3) {
        .. code block ..
    }
    else if(d > MAX4) {
        .. code block 3 ..
    }
    else if(e > MAX5) {
        .. code block 4 ..
    }
    else if(f > MAX6) {
        .. code block5 ..
    }
    else if(( a > N1) && ( b > N2)) {
            .. code block 6 ..
    }
    else if(( c > N3) && ( d > N4)) {
            .. code block 7 ..
    }
    else if (( e > N5) && ( f > N6)) {
            .. code block 8 ..
    }
    else if (( a > N1) && ( b > N2) && (d > N4)) {
            .. code block 9 ..
    }
    else if (..some combination of (a > N1) to (f > N6)...) {
            // there are more than 30 such combinations in my code
            .. code block XX ..
    }
    else {
            .... code block ....
    }

6 个答案:

答案 0 :(得分:0)

你所拥有的东西似乎并不合理,但如果你真的想重构,你可以创建一个枚举

枚举类CaseSelect {CASE0,CASE1,CASE2};

然后创建一个与当前if树非常相似的函数,每个代码块返回相应的枚举。

然后使用枚举创建一个case语句,每个

中都有相应的逻辑

它不会给你带来太大的好处,但它将选择状态的逻辑与操作逻辑分开,这对于多行语句的情况可能是有益的

答案 1 :(得分:0)

您当然可以首先将a引导至fMAXN放入数组(这只是一个我可以展开的草图,其中包含有关您的条件的更多信息,代码块和用途):

const int MAX[6] = { ... };
const int N[6] = { ... };
const std::function funcs[6];

void f(int in[6])
{
    for(int i = 0; i < 6; ++i)
    {
        if(in[i] > MAX[i])
        {
            funcs[i]();
            break;
        }
    }
}

答案 2 :(得分:0)

所以假设你有一个离散数N的互斥整数范​​围(xi到yi),你想根据给定输入z的范围调用一些代码块,然后:

  • 您想使用std::map二叉树来存储每个范围的起点和相应的lambda。
  • 在z上调用std::lower_bound以查找候选范围
  • 然后检查该范围的上限与z。
  • 如果在里面,请调用lambda

与O(n)相比,这将给出大的if-else链的O(log(N))时间。

答案 3 :(得分:0)

函数中最多有64个代码块,每个代码块可以使用匿名函数或命名函数:

my_func_array[64] = {
    [CONDITION(1,0,0,0,0,0)] = { codeblock1 },
    [CONDITION(0,1,0,0,0,0)] = { codeblock2 },
     ...
};

宏将基本上将6个第一个输入连接到索引,实质上转换为:

 my_func_array[64] = {
    [32] = { ... },
    [16] = { ... },
 };

意味着您不必以任何特定顺序输入条件......

运行时,您还必须评估所有条件:

 int condition = CONDITION(a < MAX1, b < MAX2, c < MAX2, ...);
 if (my_func_array[condition])
      my_func_array[condition]();
 else
 {
      // this second block should cover all the other cases
      int condition2 = CONDITION(a < N1, b < N2, c < N3, ... );
      if (my_func_array2[condition2])
          my_func_array2[condition2]();
 }

答案 4 :(得分:0)

首先,我会删除前6个分支Mark B建议但

  • 而不是break我会return

  • 我只是使用函数指针,std::function是一种矫枉过正 这里,

  • 我会使用std::array并绑定检查而不是原始数组。

既然枯燥的情况已经消失,我会将相同的模式应用于剩余的分支,但这需要一些技巧,因为这些条件是复合材料。

我假设MAX1 > N1。我希望这是真的。

首先,我将构建一个十进制数,编码所有参数:

int arg=10^5*(a>N1?1:0)+10^4*(b>N2?1:0)+10^3*(c>N3?1:0)+10^2*(d>N4?1:0)+10*(e>N5?1:0)+(f>N1?1:0)

我也会以类似的方式编码条件。例如:条件(a > N1) && ( b > N2)变为arg >= 110000等等。

如您所见,在此编码之后,您可以以与前6个分支相同的方式消除剩余分支。

如果效率是一个主要问题,你可以用2的幂(位移,然后使用位掩码)做同样的技巧。我没有做点小提琴,所以我无法帮助你,但它的工作方式相同,效率更高。可能和你现在拥有的if-else if链一样高效,或者更高效,因为你没有重复相同的比较。

希望这有帮助。

答案 5 :(得分:-1)

如果有很多规则,那么函数对象(例如:lambdas)可以用于救援:

我为了示范目的简化了一点,只有3个参数......

我认为非检查有一个安全的价值,在这种情况下,0(没有它可以生存,但那样看起来会更加丑陋)。

#include <iostream>
#include <functional>

struct Rule {
    int a;
    int b;
    int c;
    std::function<int()> fun;
};

Rule rules[]{
    { 10, 0, 0, []() { std::cout << "First!"; return 0;} },
    { 0, 20, 0, []() { std::cout << "Second!"; return 1;} }
};

int f(int a, int b, int c) {
    for (Rule rule : rules) {
        if ((rule.a == 0 || a > rule.a)
         && (rule.b == 0 || b > rule.b)
         && (rule.c == 0 || c > rule.c))
            return rule.fun();
    }
    std::cout << "Not match!";
    return 2;
}

int main() {
    f(5, 23, 3);
};