2013-08-06 2 views
3

Какова наилучшая практика рефакторинга для этого в Java?Refactor (C) псевдо-код для удаления goto

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: 
    ... 
}  
+0

Что касается подавления gotos, другие предоставленные ответы. Что касается части java: каковы ваши ожидания? Вы ищете объектно-ориентированный рефакторинг? –

+0

Нет, просто управление потоком. – fadedbee

+0

Зачем реорганизовывать этот код? Код читаем и легко отслеживаем. Почему вы не хотите удалять утверждения 'goto'? – Bart

ответ

3

Сначала нужно определить, что код пытается выполнить:

  • Выполните следующие действия снова и снова:
  • Зов try_something() до MAX_ATTEMPT раз, перезапуск, если он никогда не возвращает истину.
  • Вызов 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. 

} 

Есть много других способов, чтобы выразить это. Например, вы могли бы сломать каждый шаг в методе, и воспользоваться тем, что & & прекратит оценивать свои аргументы, когда одна ложь:

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

или любой другой. Я не уверен, что я бы назвал последнее «лучшей практикой», поскольку он немного запутан (это не значит, что это не подходит в определенных ситуациях), но это всего лишь пример. В общем, при переносе на другой язык: проанализировать оригинал -> что он должен делать? -> reimplement на целевом языке. Приоритет - это правильность кода, вторая (но далеко не позади) является ясностью.

+0

Спасибо, я уже сделал ваше первое решение, но мне не понравился объем i. Похоже, мне нужно будет придерживаться этого, потому что лучшего ответа здесь нет. – fadedbee

+0

Дело в том, что исходный код использовал 'goto', потому что информация о состоянии успеха/повтора не была доступна за пределами циклов повтора. Независимо от того, какое решение вы используете, если вы хотите избежать переходов стиля «goto», вам нужно каким-то образом передать информацию о состоянии одного шага на следующий шаг. –

-2

похоже, что вы можете просто заменить goto инструкцией break.

Редактировать: ninja'd!

+0

Нет, он не может, потому что после каждого цикла 'for' происходит' continue'. – phoxis

+0

oops, стыдно за меня, слишком быстро переглядываясь. – Gimby

+0

-1 есть второй взгляд: continue будет зацикливаться на while while –

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

Надежда, что помогает.

+0

Вы хотите остановить цикл после первого найденного успеха. – Lundin

+1

@ Lundin, поэтому условие цикла добавляет аддон '&&! Success'. – SJuan76

+0

Извините, я буду внимательно смотреть в следующий раз :) – Lundin

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); 
    } 
+0

Это мило, но OP попросил рефакторинг в Java, и это не Java. –

+0

@TedHopp: Я сначала пересматривал код C. – jxh

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

+1, гораздо приятнее, чем моя попытка. – jxh

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; 
    ... 
} 
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, я полагаю, вы бы поменять каждое состояние для объекта класса, где класс имеет попробовать функция.

Смежные вопросы