Come gestire la bandiera in più if-else


10

Mi sembra di vederlo abbastanza spesso nel mio codice e in altri. Non c'è nulla che sembri terribilmente sbagliato, ma mi dà fastidio dato che sembra che possa essere fatto meglio. Suppongo che un'istruzione case, potrebbe avere un po 'più di senso, ma spesso la variabile è un tipo che non funziona bene o affatto con le istruzioni case (a seconda della lingua)

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

Sembra che ci siano molti modi per "fattorizzare" questo, come ad esempio 2 set di if-elses, in cui un set gestisce quando Flag == true.

Esiste un "buon modo" per tener conto di questo, o forse quando questo algoritmo if-else si verifica di solito significa che stai facendo qualcosa di sbagliato?


6
potrebbe essere possibile passare la variabile Flag al doFooX che potrebbe gestire la bandiera stessa?
Jean-François Côté,

certo ma poi hai solo un metodo doFooX, che valuta se il flag è vero e quindi fa doFooX1 o doFooX2
TruthOf42

5
IMHO, sarà ancora più chiaro da leggere. Quindi dipende da cosa fanno DoFooA e doFooA2 ...
Jean-François Côté,

2
Perché scrivere if (Flag == true)piuttosto che solo If (Flag)? Se pensi che If (Flag == true)sia meglio, perché no if ((Flag == true) == true)?
Keith Thompson,

1
L'asporto più importante della maggior parte delle risposte di seguito è che la semplicità e la leggibilità sono molto più importanti dei trucchi intelligenti quando si tratta di flusso logico e mantenimento del codice nel futuro.
Patrick Hughes,

Risposte:


18

Potrebbe essere gestito con polimorfismo.

factory(var, flag).doFoo();

Ogni volta che hai un sacco di controlli if / else sul tipo di qualcosa, potresti considerare di centralizzare il controllo if / else in un metodo factory, quindi chiamare doFoo () polimorficamente. Ma questo potrebbe essere over-kill per una soluzione 1-off.

Forse potresti creare una mappa chiave / valore in cui la chiave è var / flag e il valore è la funzione stessa.

do[var, flag]();

2
+1: Le ricerche nella tabella battono quasi ogni volta le istruzioni nidificate.
Kevin Cline l'

1
Voglio dire che questa è la soluzione migliore.
The Muffin Man,

6

I if multipli nidificati aumentano la complessità ciclomatica del codice. Fino a poco tempo fa, avere più punti di uscita in una funzione era considerato codice strutturato male, ma ora, fintanto che il codice è semplice e breve , puoi farlo, rendendo il codice banale da leggere:

    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

un'altra opzione è combinare if e switch. Questo non è superiore alla tecnica if nidificata, ma può ridurre il numero di test duplicati (se l'interruttore si ottimizza su una tabella di salto).


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

Bene, c'è sempre questo ...

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

Ma francamente, penso che il codice originale non sia per niente male in primo luogo.


0

Usa il polimorfismo e una rulematrice

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

O come mike30suggerito: se le condizioni della regola possono facilmente formare una chiave, una hashmap è il modo migliore di procedere.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.