Як поводитися з прапором у кількох if-else's


10

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

If variable == A
    if (Flag == true)
        doFooA()
    else
        doFooA2

else if variable == B
    if (Flag == true)
        doFooB()
    else
        doFooB2
else if variable == C
    if (Flag == true)
        doFooC()
    else
        doFooC2

Здається, існує декілька способів "фактор" цього, наприклад, 2 набори if-elses, де один набір обробляє, коли Flag == true.

Чи є "хороший спосіб" визначити це чи, можливо, коли цей алгоритм if-else відбувається, це означає, що ви робите щось не так?


6
чи можна було б передати змінну прапор до doFooX, яка могла б мати справу з самим прапором?
Жан-Франсуа Кот

звичайно, але тоді у вас просто є метод doFooX, який визначає, чи прапор є істинним, а потім чи doFooX1, або doFooX2
TruthOf42,

5
ІМХО, все одно буде зрозуміліше читати. Тоді залежить від того, що роблять doFooA і doFooA2 ...
Жан-Франсуа Кот

2
Чому писати, if (Flag == true)а не просто If (Flag)? Якщо ви вважаєте, що If (Flag == true)це краще, чому б і ні if ((Flag == true) == true)?
Кіт Томпсон

1
Найважливіший вихід із більшості відповідей нижче - простота та розбірливість набагато важливіші, ніж розумні хитрощі, якщо мова йде про логічний потік та збереження коду у майбутньому.
Патрік Хьюз

Відповіді:


18

З цим можна впоратися з поліморфізмом.

factory(var, flag).doFoo();

Кожного разу, коли у вас є купа перевірки if / else на тип чогось, ви можете розглянути можливість централізації перевірки if / else у фабричному методі, а потім викликати doFoo () поліморфно. Але це може бути надмірним вбивством для одноразового рішення.

Можливо, ви могли б створити карту ключа / значення, де ключ - var / flag, а значення - сама функція.

do[var, flag]();

2
+1: Пошукові таблиці перемагають вкладені if-операції майже кожного разу.
кевін клайн

1
Хочу сказати, що це найкраще рішення.
The Muffin Man

6

Кілька вкладених ifs збільшують циклічну складність коду. До недавнього часу наявність декількох точок виходу у функції функціонував погано структурований код, але тепер, поки код простий і короткий , ви можете це зробити, зробивши код тривіальним для читання:

    if (variable == A && Flag) {
        doFooA();
        return;
    }

    if (variable == A) {
        doFooA2();
        return;
    }

    if (variable == B && Flag){
        doFooB();
        return;
    }

    if (variable == B){
        doFooB2();
        return;
    }

    if (variable == C && Flag){
         doFooC();
         return;
    }

    if (variable == C){
         doFooC2();
    }

    return;

3

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


if (flag)
{
    switch (variable)
    {
        case A:
           ... blah
           break;

        case B:
           ... blah
           break;

        case C:
           ... blah
           break;

        default:
           ... log an error.
           ... maybe do a default action.
           break;
    }
}
else // flag == false
{
    switch (variable)
    {
        case A:
           ... blah
           break;

        case B:
           ... blah
           break;

        case C:
           ... blah
           break;

        default:
           ... log an error.
           ... maybe do a default action.
           break;
}

0

Що ж, завжди є таке ...

if variable == A && Flag
    doFooA()
else if variable == A 
    doFooA2    
else if variable == B && Flag
    doFooB()
else if variable == B
    doFooB2
else if variable == C && Flag
     doFooC()
else if variable == C
     doFooC2

Але, чесно кажучи, я думаю, що первинний код не є наполовину поганим.


0

Використовуйте поліморфізм і ruleмасив

interface IRule() {
  boolean applicable(args...);
  obj apply(args...);
}

static final Array<IRule> rules = [new MeaningfulNameRule1(), new MeaningfulNameRule2(), ...];

/* where */
class MeaningfulNameRuleX extends IRule{ /* */ }

/* In your method */

for (rule in rules) {
  if (rule.applicable(a,b,c)){
    return rule.apply(e,f,g);
  }
}

Або як mike30запропоновано: Якщо умови правила можуть легко сформувати ключ, то хешмап - це найкращий спосіб.

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