3

What is the best practise refactoring for this in Java?

while (1) {
  // initialisation

  for (int i = 0; i < MAX_ATTEMPT; i++) {
    if (try_something()) goto step2;
  }
  continue;

step2:  
  for (int i = 0; i < MAX_ATTEMPT; i++) {
    if (try_next_thing()) goto step3;
  }
  continue;

step3:
  ...
}    
4

7 回答 7

3

您首先要确定代码试图完成的任务:

  • 一遍又一遍地执行以下操作:
  • 调用 try_something() 最多 MAX_ATTEMPT 次,如果它永远不会返回 true,则重新启动。
  • 调用 try_next_thing() 最多 MAX_ATTEMPT 次,如果它永远不会返回 true,则重新启动。

然后,编写执行此操作的代码,例如:

while (true) {

    int i;

    for (i = 0; i < MAX_ATTEMPT && !try_something(); ++ i)
        ;
    if (i == MAX_ATTEMPT)
        continue;

    for (i = 0; i < MAX_ATTEMPT && !try_next_thing(); ++ i)
        ;
    if (i == MAX_ATTEMPT)
        continue;

    // etc.

}

还有很多其他的方式来表达这一点。例如,您可以将每个步骤分解为一个方法,并利用 && 将在其中一个为 false 时停止评估它的参数这一事实:

boolean doFirstThing () {
    int i;
    for (i = 0; i < MAX_ATTEMPTS && !try_something(); ++ i)
        ;
    return i < MAX_ATTEMPTS;
}

boolean doSecondThing () {
    int i;
    for (i = 0; i < MAX_ATTEMPTS && !try_other_thing(); ++ i)
        ;
    return i < MAX_ATTEMPTS;
}

// then, elsewhere
while (true)
    doFirstThing() && doSecondThing();

管他呢。我不确定是否将后者称为“最佳实践”,因为它有点混淆(这并不是说它在某些情况下不合适),但这只是一个例子。一般来说,移植到另一种语言时:分析原始语言 -> 它应该做什么?-> 用目标语言重新实现。优先级是代码的正确性,其次(但也不远)是清晰度。

于 2013-08-06T09:20:53.813 回答
2

我很想封装这些步骤并使用状态机之类的东西:

enum Step {
    STEP1 {
        @Override
        public Step attempt() {
            for (int i = 0; i < MAX_ATTEMPT; i++) {
                if (try_something()) return STEP2; // advance to next step
            }
            return STEP1; // return to step 1
        }
    },
    STEP2 {
        @Override
        public Step attempt() {
            for (int i = 0; i < MAX_ATTEMPT; i++) {
                if (try_next_thing()) return STEP3; // advance to next step
            }
            return STEP1; // return to step 1
        }
    },
    STEP3 { /* etc. */ },
    . . .
    ;
    public abstract Step attempt();
}

然后(如果我理解原来的意大利面条逻辑)你可以把你的循环写成:

Step step = Step.STEP1;
while (1) {
    // initialisation

    step = step.attempt();
}
于 2013-08-06T09:37:22.683 回答
2

对于文字,但不是你能做的最好的翻译。除非您必须生成代码并且没有简单的解决方法,否则使用 break 作为 goto 并不是一个好主意。

while (true) {
    // initialisation

    step2:
    {
        for (int i = 0; i < MAX_ATTEMPT; i++) {
            if (try_something()) break step2;
        }
        continue;
    }

    step3:
    {
        for (int i = 0; i < MAX_ATTEMPT; i++) {
            if (try_next_thing()) break step3;
        }
        continue;
    }

    step4:
    ...
}
于 2013-08-06T09:25:03.297 回答
1

也许不是最好的解决方案,但我通常会这样做:

boolean success = false;

for (int i = 0; i < MAX_ATTEMPT && !success; i++) {
    success = try_something()
}

if (success) {
    success = false;
    for (int i = 0; i < MAX_ATTEMPT && !success; i++) {
        success = try_next_thing();
    }
}

希望有帮助。

于 2013-08-06T09:26:55.967 回答
0

首先将代码转换为 C 中的面向对象设计。您的代码本质上是一个状态机,因此您应该能够将其替换为一个状态机。

典型的基于函数指针的状态机示例:

typedef bool (state_t*)(void);

state_t state [STATES_N] = {   // array of function pointers
  &try_something,
  &try_next_thing,
  ...
};


int state = 0;  

while (1) {

  for (int i = 0; i < MAX_ATTEMPT; i++) {

    if(try[state]()) {
      state++;
      if(state == STATES_N) {
        state = 0;
      }
    }
  }
}

要将其转换为 Java OO,我想您会将每个状态交换为类的一个对象,该类具有一个 try 函数。

于 2013-08-06T11:14:27.993 回答
0

最适合我的是跨函数拆分逻辑,这就是我的想法:

bool attempt_something() {
   for(int i = 0; i < MAX_ATTEMPT: i++) {
      if (try_something())
         return true;
   }
   return false;
}

bool attempt_something_else() {
   for(int i = 0; i < MAX_ATTEMPT: i++) {
      if (try_something_else())
         return true;
   }
   return false;
}

你的时间会变成

while (1) {
   if (!attempt_something())
      continue;
   if (!attempt_something_else())
      continue;
   ...
}
于 2013-08-06T09:55:27.607 回答
0

我会首先将 C 代码重构为不那么重复的代码:

enum { STEP1, STEP2, STEP3, /*...*/ };

typedef int ThingToTry();

ThingToTry *things_to_try[MAX_STEP] = {
    try_something,
    try_next_thing,
    /*...*/
};

int next_step (int (*thing_to_try)(), int true_step, int false_step) {
    for (int i = 0; i < MAX_ATTEMPT; i++) {
        if (thing_to_try()) return true_step;
    }
    return false_step;
}

/*...*/

    step = STEP1;
    while (step != MAX_STEP) {
        if (step == STEP1) {
            /*...initialization */
        }
        step = next_step(things_to_try[step], step+1, STEP1);
    }

Java中对应的代码:

enum StepEnum { STEP1, STEP2, STEP3, //...
              }

interface ThingToTry {
   bool do_it ();
}

class TrySomething extends ThingToTry //...
class TryNextThing extends ThingToTry //...

StepEnum next_step (ThingToTry thing_to_try,
                    StepEnum true_step, StepEnum false_step) {
    for (int i = 0; i < MAX_ATTEMPTS; ++i) {
        if (thing_to_try.do_it()) return true_step;
    }
    return false_step;
}

//...
    ThingToTry[MAX_STEP] things_to_try = {
        new TrySomething,
        new TryNextThing,
        //...
    };

    while (step != MAX_STEP) {
        if (step == STEP1) {
            //...initialization
        }
        StepEnum true_step = StepEnum.values()[step.ordinal()+1];
        step = next_step(things_to_try[step.ordinal()], true_step, STEP1);
    }
于 2013-08-06T09:29:04.950 回答