Как обрабатывать флаг в нескольких if-else

10

Я, кажется, вижу это достаточно часто в своем коде и других. В этом нет ничего ужасного, но меня это раздражает, поскольку кажется, что это можно сделать лучше. Я предполагаю, что оператор case может иметь немного больше смысла, но часто переменная является типом, который не работает хорошо или вообще не работает с операторами case (в зависимости от языка)

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.

Есть ли «хороший способ» это учесть, или, возможно, когда происходит алгоритм «если-то еще», это обычно означает, что вы делаете что-то не так?

TruthOf42
источник
6
Можно ли передать переменную Flag в 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]();
mike30
источник
2
+1: поиск таблиц бьет вложенные операторы if почти каждый раз.
Кевин Клайн
1
Я хочу сказать, что это лучшее решение.
Человек
6

Несколько вложенных if увеличивают цикломатическую сложность кода. До недавнего времени наличие нескольких точек выхода в функциях считалось плохо структурированным кодом, но теперь, пока код прост и короток , вы можете сделать это, сделав код тривиальным для чтения:

    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 и switch. Это не превосходит вашу вложенную технику, но может уменьшить количество повторяющихся тестов (если коммутатор оптимизируется под таблицу переходов).


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;
}
DWB
источник
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предложено: если условия правила могут легко сформировать ключ, тогда наилучшим способом будет использование хэш-карты.

Матиас
источник