Como lidar com sinalizador em vários if-else

10

Parece que vejo isso com frequência suficiente no meu código e em outros. Não há nada que pareça terrivelmente errado, mas isso me incomoda, pois parece que pode ser feito melhor. Suponho que uma declaração de caso possa fazer um pouco mais de sentido, mas muitas vezes variável é um tipo que não funciona bem ou de modo algum com declarações de caso (dependendo do idioma)

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

Parece que há várias maneiras de "fatorar" isso, como 2 conjuntos de if-elses, nos quais um conjunto lida quando Flag == true.

Existe uma "boa maneira" de fatorar isso, ou talvez quando esse algoritmo if-else acontece, geralmente significa que você está fazendo algo errado?

TruthOf42
fonte
6
seria possível passar a variável Flag para o doFooX que pudesse lidar com a própria flag?
Jean-François Côté
certo, mas então você só tem um método doFooX, que avalia se o sinalizador é verdadeiro e, em seguida, faz tanto doFooX1 ou doFooX2
TruthOf42
5
IMHO, ainda será mais claro ler. Em seguida, ele depende o que doFooA e doFooA2 fazer ...
Jean-François Côté
2
Por que escrever em if (Flag == true)vez de apenas If (Flag)? Se você acha que If (Flag == true)é melhor, por que não if ((Flag == true) == true)?
Keith Thompson
11
A dica mais importante da maioria das respostas abaixo é que simplicidade e legibilidade são muito mais importantes do que truques inteligentes quando se trata de fluxo lógico e manutenção do código no futuro.
Patrick Hughes

Respostas:

18

Pode ser manuseado com polimorfismo.

factory(var, flag).doFoo();

Sempre que você tiver várias verificações de if / else no tipo de algo, considere centralizar a verificação de if / else em um método de fábrica, e então chame doFoo () polimorficamente. Mas isso pode ser um extermínio para uma solução pontual.

Talvez você possa criar um mapa de chave / valor em que a chave seja var / flag e o valor seja a própria função.

do[var, flag]();
mike30
fonte
2
+1: as pesquisas de tabela superam as declarações if aninhadas quase todas as vezes.
kevin Cline
11
Eu quero dizer que esta é a melhor solução.
O homem de muffin
6

Vários ifs aninhados aumentam a complexidade ciclomática do código. Até recentemente, ter vários pontos de saída em uma função era considerado código estruturado incorreto, mas agora, desde que o código seja simples e curto , você pode fazê-lo, tornando o código simples de ler:

    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
fonte
3

outra opção é combinar if e switch. Isso não é superior à sua técnica aninhada, mas pode reduzir o número de testes duplicados (se a opção otimizar para uma tabela de 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;
}
DwB
fonte
0

Bem, sempre há isso ...

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

Mas, francamente, acho que o código original não é tão ruim em primeiro lugar.

Ross Patterson
fonte
0

Use polimorfismo e uma rulematriz

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

Ou como mike30sugerido: se as condições da regra puderem facilmente formar uma chave, um hashmap é o melhor caminho a percorrer.

Matyas
fonte