Jak obsługiwać flagę w wielu if-else

10

Wydaje mi się, że dość często to widzę w moim kodzie i innych. Nie ma w tym nic strasznie złego, ale denerwuje mnie, ponieważ wygląda na to, że można to zrobić lepiej. Przypuszczam, że instrukcja case może mieć trochę więcej sensu, ale często zmienna jest typem, który nie działa dobrze lub wcale z instrukcjami case (w zależności od języka)

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

Wydaje się, że istnieje wiele sposobów na „uwzględnienie” tego, na przykład 2 zestawy if-elses, gdzie jeden zestaw obsługuje, gdy Flag == true.

Czy istnieje „dobry sposób” na uwzględnienie tego, a może kiedy ten algorytm się dzieje, zwykle oznacza to, że robisz coś źle?

TruthOf42
źródło
6
czy możliwe jest przekazanie zmiennej Flag do doFooX, który mógłby poradzić sobie z samą flagą?
Jean-François Côté
jasne, ale wtedy masz po prostu metodę doFooX, która ocenia, czy flaga jest prawdziwa, a następnie robi doFooX1 lub doFooX2
TruthOf42
5
IMHO, nadal będzie bardziej czytelny. To zależy od tego, co robią doFooA i doFooA2 ...
Jean-François Côté
2
Po co pisać, if (Flag == true)a nie tylko If (Flag)? Jeśli uważasz, że tak If (Flag == true)jest lepiej, dlaczego nie if ((Flag == true) == true)?
Keith Thompson,
1
Najważniejszym odejściem od większości poniższych odpowiedzi jest to, że prostota i czytelność są o wiele ważniejsze niż sprytne sztuczki, jeśli chodzi o logiczny przepływ i utrzymanie kodu w przyszłości.
Patrick Hughes,

Odpowiedzi:

18

Można sobie z tym poradzić z polimorfizmem.

factory(var, flag).doFoo();

Ilekroć masz kilka sprawdzeń typu if / else na typie czegoś, możesz rozważyć scentralizowanie sprawdzania if / else w metodzie fabrycznej, a następnie wywołać polimorficznie metodę doFoo (). Ale może to być nadmierne zabójstwo dla rozwiązania jednorazowego.

Może mógłbyś stworzyć mapę klucz / wartość, w której kluczem jest var / flag, a wartością jest sama funkcja.

do[var, flag]();
mike30
źródło
2
+1: Wyszukiwanie tabel prawie za każdym razem bije zagnieżdżone instrukcje if.
kevin cline
1
Chcę powiedzieć, że to najlepsze rozwiązanie.
The Muffin Man,
6

Wiele zagnieżdżonych ifs zwiększa cykliczną złożoność kodu. Do niedawna posiadanie wielu punktów wyjścia w funkcjach było uważane za źle skonstruowany kod, ale teraz, o ile kod jest prosty i krótki , możesz to zrobić, dzięki czemu kod jest trywialny:

    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;
Tulains Córdova
źródło
3

inną opcją jest połączenie if i przełączanie. Nie jest to lepsze niż technika zagnieżdżenia, ale może zmniejszyć liczbę zduplikowanych testów (jeśli przełącznik zoptymalizuje się do tabeli skoków).


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
źródło
0

Cóż, zawsze jest to ...

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

Ale szczerze mówiąc, myślę, że oryginalny kod nie jest w połowie taki zły.

Ross Patterson
źródło
0

Użyj polimorfizmu i ruletablicy

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

Lub zgodnie z mike30sugestią: jeśli warunki reguły mogą z łatwością utworzyć klucz, najlepszym rozwiązaniem jest hasztapa.

Matyas
źródło