Найкращий спосіб форматування оператора if з кількома умовами


88

Якщо ви хочете, щоб якийсь код виконувався на основі двох або більше умов, який найкращий спосіб відформатувати оператор if?

перший приклад: -

if(ConditionOne && ConditionTwo && ConditionThree)
{
   Code to execute
}

Другий приклад: -

if(ConditionOne)
{
   if(ConditionTwo )
   {
     if(ConditionThree)
     {
       Code to execute
     }
   }
}

що найпростіше зрозуміти та прочитати, маючи на увазі, що кожна умова може бути довгою назвою функції або чимось.


Шкода, що ніхто на цій сторінці не згадує підрядок "швидко" або "продуктивність". Ось чому я прийшов сюди вчитися.
Президент

Відповіді:


131

Я віддаю перевагу варіанту А

bool a, b, c;

if( a && b && c )
{
   //This is neat & readable
}

Якщо у вас є особливо довгі змінні / умови методу, ви можете просто розбити їх

if( VeryLongConditionMethod(a) &&
    VeryLongConditionMethod(b) &&
    VeryLongConditionMethod(c))
{
   //This is still readable
}

Якщо вони ще більш складні, то я б подумав про те, щоб робити методи умови окремо поза оператором if

bool aa = FirstVeryLongConditionMethod(a) && SecondVeryLongConditionMethod(a);
bool bb = FirstVeryLongConditionMethod(b) && SecondVeryLongConditionMethod(b);
bool cc = FirstVeryLongConditionMethod(c) && SecondVeryLongConditionMethod(c);

if( aa && bb && cc)
{
   //This is again neat & readable
   //although you probably need to sanity check your method names ;)
}

IMHO Єдиною причиною для варіанту "B" було б, якщо у вас є окремі elseфункції для запуску для кожної умови.

напр

if( a )
{
    if( b )
    {
    }
    else
    {
        //Do Something Else B
    }
}
else
{
   //Do Something Else A
}

Мені це подобається. Хоча я не шанувальник ідеї методу, якщо методи вже не існують і не повертають логічне значення.
Томас Оуенс

2
Ви не оцінюєте все без причини у другому прикладі?
Одіс

Я б використовував '&&' перед умовою. Важко мати умови з такою ж довжиною символів, як у прикладі.
Дарков

28

Інші відповіді пояснюють, чому перший варіант зазвичай найкращий. Але якщо у вас кілька умов, спробуйте створити окрему функцію (або властивість), виконуючи перевірку умов у варіанті 1. Це полегшує читання коду, принаймні, коли ви використовуєте хороші імена методів.

if(MyChecksAreOk()) { Code to execute }

...

private bool MyChecksAreOk()
{ 
    return ConditionOne && ConditionTwo && ConditionThree;
}

Якщо умови покладаються лише на локальні змінні області, ви можете зробити нову функцію статичною і передати все, що вам потрібно. Якщо є суміш, передайте місцеві речі.


2
Я виявив, що це найефективніше та простіше додати умови пізніше
pbojinov

+1 спочатку я підняв брову, але це дійсно найкраща відповідь imho. наявність цього логічного значення isOkToDoWhateverяк властивості має багато сенсу.
Грінч

1
Але це просто зміщує ту саму складну умову в іншому місці, де її також потрібно читати, щоб ми знову повернулися до цього. Мова йде не лише про ifчитаність висловлювань, а швидше про читаність умов.
Роберт Коритник

@RobertKoritnik Я розумію, що ви говорите, але я не думаю, що ми повернулися до першого, тому що ми зменшили складність, яку читач повинен врахувати за один раз. Вона може переглянути умови, АБО вона може переглянути код, використовуючи умови, де умови мають (сподіваємось) приємне ім’я. Принаймні мені часто так легше перебирати, але знову ж таки іноді приємно мати усі деталі в одному місці. Як завжди, це залежить.
Торбьорн,

Чудовий момент - використання хороших імен методів та рефакторинг логіки.
JB Lovell

10

Перший приклад є більш "легким для читання".

Насправді, на мою думку, вам слід використовувати лише другий, коли вам потрібно додати якусь «інакшу логіку», але для простого Умовного використовуйте перший смак. Якщо вас турбує довгий стан, ви завжди можете використовувати наступний синтаксис:

if(ConditionOneThatIsTooLongAndProbablyWillUseAlmostOneLine
                 && ConditionTwoThatIsLongAsWell
                 && ConditionThreeThatAlsoIsLong) { 
     //Code to execute 
}

Щасти!


9

На запитання було задано і досі відповідали так, ніби рішення повинно прийматись виключно на "синтаксичній" основі.

Я б сказав, що правильна відповідь про те, як ви викладаєте низку умов в if, також повинна залежати від "семантики". Отже, умови слід розбити та згрупувати відповідно до того, що відбувається «концептуально».

Якщо два тести насправді є двома сторонами однієї медалі, наприклад. якщо (x> 0) && (x <= 100), то складіть їх разом на одному рядку. Якщо інша умова концептуально набагато більш віддалена, наприклад. user.hasPermission (Admin ()), а потім поставте його на власний рядок

Напр.

if user.hasPermission(Admin()) {
   if (x >= 0) && (x < 100) {
      // do something
   }
}

7
if (   ( single conditional expression A )
    && ( single conditional expression B )
    && ( single conditional expression C )
   )
{
   opAllABC();
}
else
{
   opNoneABC();
}

Форматування декількох умовних виразів у операторі if-else таким чином:

  1. дозволяє збільшити читабельність:
    a. усі двійкові логічні операції {&&, ||} у виразі, показаному першим
    b. обидва умовні операнди кожної двійкової операції очевидні, оскільки вони вирівнюються вертикально
    c. Операції з вкладеними логічними виразами стають очевидними за допомогою відступу, як і вкладання операторів усередині речення
  2. вимагає явних дужок (не покладатися на правила пріоритету оператора)
    a. це дозволяє уникнути типових помилок статичного аналізу
  3. дозволяє полегшити налагодження
    a. вимкнути окремі одиночні умовні тести лише за допомогою a //
    b. встановити точку розриву безпосередньо перед або після будь-якого окремого тестування
    ...
// disable any single conditional test with just a pre-pended '//'
// set a break point before any individual test
// syntax '(1 &&' and '(0 ||' usually never creates any real code
if (   1
    && ( single conditional expression A )
    && ( single conditional expression B )
    && (   0
        || ( single conditional expression C )
        || ( single conditional expression D )
       )
   )
{
   ... ;
}

else
{
   ... ;
}

Це мій метод. Єдина проблема у мене - я ще не знайшов засоби
покращення


3

Перший з них простіший, тому що, якщо ви читаєте його зліва направо, ви отримуєте: "Якщо щось І щось інше І щось інше ТОГО", - це легко зрозуміле речення. Другий приклад читає "Якщо щось THEN, якщо щось інше THEN, якщо щось інше THEN", що є незграбним.

Крім того, подумайте, чи хочете ви використовувати деякі АБО у своєму реченні - як би ви це зробили у другому стилі?


0

У Perl ви можете зробити це:

{
  ( VeryLongCondition_1 ) or last;
  ( VeryLongCondition_2 ) or last;
  ( VeryLongCondition_3 ) or last;
  ( VeryLongCondition_4 ) or last;
  ( VeryLongCondition_5 ) or last;
  ( VeryLongCondition_6 ) or last;

  # Guarded code goes here
}

Якщо якась із умов не виконується, вона просто продовжиться, після блокування. Якщо ви визначаєте будь-які змінні, які ви хочете зберегти після блоку, вам потрібно буде визначити їх перед блоком.


1
Це виглядає Перліш - у "це робить ЩО?" сенс;) Але насправді це читається, як тільки ви звикнете.
Пісквор залишив будівлю

-2

Я давно стикаюся з цією дилемою і досі не можу знайти належного рішення. На мій погляд, єдиним хорошим способом є спочатку спробувати позбутися умов раніше, щоб ви не раптом порівняли 5 з них.

Якщо альтернативи немає, тоді, як пропонували інші, - розбийте її на окремі та скоротіть імена або згрупуйте їх, і, наприклад, якщо все має бути істинним, використовуйте щось на кшталт "якщо в масиві x немає false, тоді запустіть".

Якщо все не вдається, @Eoin Campbell дав досить хороші ідеї.


Це не додає нічого нового до вже існуючих відповідей.
джерні

-4

Коли стан справді складний, я використовую такий стиль (приклад реального життя PHP):

if( $format_bool &&
    (
        ( isset( $column_info['native_type'] )
            && stripos( $column_info['native_type'], 'bool' ) !== false
        )
        || ( isset( $column_info['driver:decl_type'] )
            && stripos( $column_info['driver:decl_type'], 'bool' ) !== false
        )
        || ( isset( $column_info['pdo_type'] )
            && $column_info['pdo_type'] == PDO::PARAM_BOOL
        )
    )
)

Я вважаю, що це приємніше і читабельніше, ніж вкладання декількох рівнів if(). І в деяких випадках, подібних до цього, ви просто не можете розбити складні умови на частини, оскільки в іншому випадку вам доведеться if() {...}багато разів повторювати ті самі оператори в блоці.

Я також вважаю, що додати трохи «повітря» в код - це завжди гарна ідея. Це значно покращує читабельність.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.