2013-08-30 2 views
8

Когда поток кода, как это:Каковы некоторые лучшие способы избежать do-while (false); взломать Java?

if(check()) 
{ 
    ... 
    ... 
    if(check()) 
    { 
    ... 
    ... 
    if(check()) 
    { 
     ... 
     ... 
    } 
    } 
} 

Я вообще видел эту работу вокруг, чтобы избежать этого грязный код потока:

do { 
    if(!check()) break; 
    ... 
    ... 
    if(!check()) break; 
    ... 
    ... 
    if(!check()) break; 
    ... 
    ... 
} while(false); 

Какие лучшие способы, позволяющие избежать этого временного решения/хак так что он становится кодом более высокого уровня (отраслевого уровня)?

Существуют ли, возможно, конструкции, которые поступают из сообщества Apache или Google Guava?

Примечание: это копия the same question for C++. Лучшие ответы там действительно указатели функций и команда GOTO. Оба не существуют в Java. Я с интересом интересуюсь тем же для Java.

Ввод его в новую функцию и использование return - это, на мой взгляд, нехорошее решение, потому что возврат завершает метод. Поэтому, если у моего класса 20 методов с этими конструкциями, мне нужно добавить 20 дополнительных методов, чтобы это сделать. Вот почему GOTO был лучшим ответом для C++.

+6

Некоторые ответы по-прежнему держать - перемещение его в свою собственную функцию, и с помощью возврата к примеру. – Sinkingpoint

+0

@MarounMaroun Потому что вы можете иметь это 20 раз в функции для прохождения 20 последовательных шагов. Если я сделаю это так, в финале, если слайды уже 20 вкладок вправо, что делает код нечитаемым. –

+3

Я не религиозный человек, но я искренне верю, что «ГОТО» не является правильным ответом на все, что связано с Java. – WarrenFaith

ответ

6

Что такое «пока (ложная)» бессмысленность? Используйте ярлык!

myLabel: { 
    if(!check()) break myLabel; 
    ... 
    ... 
    if(!check()) break myLabel; 
    ... 
    ... 
    if(!check()) break myLabel; 
    ... 
} 

Это ядро ​​Java: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html

+1

Я принимаю это, потому что он значительно близок к исходному источнику. Конечно, другие ответы также очень хороши. Это касается именно проблемы, с которой сталкиваются пользователи C++ (и Java), и, очевидно, в Java существует очень простое решение. Спасибо за этот вклад. –

+1

Добро пожаловать. – mvmn

7

Чтобы уменьшить cyclomatic complexity, вы можете отделить логику в submethods:

public void go() { 
    first(); 
} 

public void first() { 
    if(check()) { 
     // #1 
     second(); 
    } 
} 

public void second() { 
    if(check()) { 
     // #2 
     third(); 
    } 
} 

public void third() { 
    if(check()) { 
     // #3 
    } 
} 
+0

Спасибо за ваш ответ. Да, ты прав насчет сложности. Тем не менее, в этом вопросе основное внимание уделяется читаемости и кодовому красоте. Скорость не является основной целью. В любом случае, я предполагаю, что современные компиляторы JIT справятся с этим штрафом. –

2

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

Этот комментарий к вашей проблеме показывает: вы представляете неправильную структуру кода.

Например ваш код, как это

if (bool) { 
    // do something 
    if (anotherBoolean) { 
     //do even more 
     if (thirdBoolean) { 
      // here we go! I spare deeper structure... 
     } 
    } 
} 

Это может быть легко переработан в:

public void method() { 
    if (bool) { 
     doSomeStuff(); 
    } 
} 

public void doSomeStuff() { 
    if (anotherBoolean) { 
     doThirdStuff(); 
    } 
} 

public void doThirdStuff() { 
    if (thirdBoolean) { 
     doEvenMore(); 
    } 
} 

public void doEvenMore() { 
    // deeper structure 
} 

Такая структура кода была бы хорошим образцом чистого кодекса методы делают их «одноцелевой» материал, вы не делаете взлома во время цикла, и вы даже можете повторно использовать методы где-то.

+0

Спасибо за этот взнос. В моем случае у меня есть 4 метода в моем классе, и они имеют более 6 логических элементов. Поэтому мне пришлось бы добавить 24 класса к классу. Теперь попробуйте найти 24 разных имени для методов. Хорошо, я aggree, это зависит от моего фактического кода. Вместо того, чтобы находить больше имен, я мог бы добавить параметры и т. Д. Таким образом, ваше решение может работать для определенных случаев. Я думал, что у кого-то может быть что-то более прохладное, например, переключатель, исключение-улов или статический импорт. Все, кроме создания новых методов. –

+1

Если ваши 6 булевых элементов, представляющих какие-то состояния, вы можете попробовать перечислить и использовать их в выражении оператора switch. Например, я использую это для обработки ввода. State.PRESSED, RELEASE, MOVING, NONE и т. Д. И вызывать методы в соответствии с этим состоянием. – WarrenFaith

-1

Здесь может быть другое решение:

public interface Stuff { 
    void run(); 
} 

private List<Stuff> stuffs; 

// logical parts 
public void init() { 
    Stuff first = new Stuff() { 
     public void run() { 
      // stuff #1 
     } 
    }; 
    Stuff second = new Stuff() { 
     public void run() { 
      // stuff #2 
     } 
    }; 
    Stuff third = new Stuff() { 
     public void run() { 
      // stuff #3 
     } 
    }; 
    // LinkedList to keep order 
    stuffs = new LinkedList<Stuff>(Arrays.asList(first, second, third)); 
} 

// main method, just launch the stuffs while check() returns true 
// no change needed when new stuff 
public void go() { 
    for (Stuff stuff : stuffs) { 
     if (!check()) break; 
     stuff.run(); 
    } 
} 

Если ваши питания могут иметь различные условия для проверки, вы можете улучшить с:

public interface Stuff { 
    void run(); 
    boolean condition(); 
} 

private List<Stuff> stuffs; 

public void init() { 
    Stuff first = new Stuff() { 
     public void run() { 
      // stuff #1 
     } 
     public boolean condition() { 
      return true; // condition to call this run() 
     } 
    }; 
    Stuff second = new Stuff() { 
     public void run() { 
      // stuff #2 
     } 
     public boolean condition() { 
      return false; // condition to call this run() 
     } 
    }; 
    Stuff third = new Stuff() { 
     public void run() { 
      // stuff #3 
     } 
     public boolean condition() { 
      return true; // condition to call this run() 
     } 
    }; 
    stuffs = new LinkedList<Stuff>(Arrays.asList(first, second, third)); 
} 

public void go() { 
    for (Stuff stuff : stuffs) { 
     if (!stuff.condition()) break; 
     stuff.run(); 
    } 
} 
+0

+1 это действительно круто. –

+3

-1 Извините. До сих пор трудно понять, что это печально. Сравните этот код с исходным кодом рефакторинга OP. Код OP более важен. Этот ответ более любопытство и анти-шаблон. – Bohemian

+1

Я не вижу в этом анти-шаблон. Звучит популистски для меня. Первый исходный код этого примера - это идеальный шаблон ООП для этой проблемы. В любом случае, второй исходный код, который был добавлен для расширения ответа, кажется, смущает всех, и теперь он выглядит как плохой ответ, который нарушает первоначальную простую проблему. –

0

Это хороший вопрос. Семантика любого решения должна включать какой-то возбуждаемый блок, будь то буквальный или подразумеваемый реализацией, которая может быть завершена.

Некоторые из других ответов настолько сложны, что они в то время как они достигают избегания цикла do-while, теряют всю ясность и удобочитаемость, что делает их «плохим» кодом.

Поразмыслив, это как бы я его код:

doSomething(); // Replace current code with a method call 

private void doSomething() { 
    if(!check()) return; 
    ... 
    ... 
    if(!check()) return; 
    ... 
    ... 
    if(!check()) return; 
    ... 
    ... 
} 

Основные моменты:

  • Метод представляет собой блок, который аккуратно вышел на return
  • три части четко функционируют как один программный блок, поэтому вместе они являются кандидатом на повторную обработку в отдельный метод.
  • Нет «приспособлений», таких как перфекционизм ORY делать, в то время как (ложь) конструкт, который существует только для обеспечения exitable блока и который может смутить другие
  • Используя отрицательные тесты, то выход, две вещей, которые достигаются:
    • «выход в начале» кодирование парадигмы
    • менее отступов/раскроя, что уменьшает cyclic complexity
  • Никакие дополнительные блоки/классов/объекты не создаются, сохраняя читаемость и производительность (хотя кадр будет помещаются в стек для вызова метода - незначительное воздействие
+0

А? Downvote? Позаботьтесь о том, почему? Мне кажется, что подход подходит для меня (хороший даже). – Bohemian

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