Composti per lo styling E / O se affermazioni

13

In che modo stili complessi composti AND / OR se le dichiarazioni per la massima leggibilità? Come indentate e dove posizionate le interruzioni di riga? La mia situazione particolare è qualcosa come la seguente. È decisamente meglio che distruggere tutto in un'unica riga, ma sembra ancora disordinato.

if (
    (
        x == y
        && a != b
        && p.isGood() 
        && (
            i + u == b
            || q >= a
        )
    )
    || k.isSomething()
    || m > n
) {
    doSomething();
}
    
posta JoJo 17.06.2011 - 00:12
fonte

8 risposte

6

Crea variabili booleane per ogni piccolo passo:

bool step1 = i + u == b || q >= a;
bool step2 = a != b && p.isGood() && group1;
bool step3 = group2 || k.isSomething() || m > n;
if (step3) { doSomething(); }

Ovviamente è simile alla risposta di Lacrymology, tranne che con nomi diversi per ogni passo.

Se chiami step1 , step2 e step3 in modi che hanno un buon senso concettuale, questo dovrebbe essere di gran lunga il più leggibile. p.isGood() e k.isSomething() a volte possono essere invocati in situazioni in cui non sarebbe nel codice originale, quindi questa non sarebbe un'opzione se quelle funzioni sono costose o se stai eseguendo questo codice in un ciclo molto stretto .

D'altra parte, non ti devi preoccupare del colpo di performance che potrebbe causare la creazione di nuove variabili; un buon compilatore li ottimizzerà.

Un esempio di rilevamento delle collisioni rettangolari (che probabilmente non utilizzeresti a causa del risultato prestazionale di cui sopra):

if((a.x + a.width >= b.x || b.x + b.width >= a.x)
 && (a.y + a.height >= b.y || b.y + b.width >= a.y)
)
{ collision(); }

Potrebbe diventare:

bool horizMatch = a.x + a.width >= b.x || b.x + b.width >= a.x;
bool vertMatch = a.y + a.height >= b.y || b.y + b.width >= a.y;
if(horizMatch && vertMatch) { collision(); }

Inoltre, se vuoi lasciare il tuo codice così com'è, penso che andrebbe benissimo anche a me. Sinceramente penso che il tuo codice sia abbastanza leggibile. Ovviamente non so quali siano esattamente a b x y i u p k m n , ma per quanto riguarda la struttura, mi sembra bello.

    
risposta data 17.06.2011 - 01:46
fonte
8

Di solito ritocco il mio codice per essere più modulare se i miei condizionali diventano così complicati.

    
risposta data 17.06.2011 - 00:23
fonte
8

Farei qualcosa di più simile a questo livello di complessità

bool doIt = x == y && a != b && p.isGood();
doIt &= ( i + u == b || q >= a);
doIt |= k.isSomething() || m > n;

if(doIt)
{
    doSomething();
}

È brutto, ma è leggibile e sono abbastanza sicuro che il compilatore saprà come refactarlo.

D'altro canto, se mai mi vedessi nella situazione di scrivere una tale dichiarazione IF, ripenserò la soluzione, perché sono CERTO che c'è un modo per farlo più semplice, o almeno per astrarre alcune di quelle condizioni ( es .: forse x == y && a != b && p.isGood() significa solo this->isPolygon() e posso fare quel metodo;

    
risposta data 17.06.2011 - 00:50
fonte
4

Sto diventando meno ossessionato dall'allineamento verticale nel tempo, ma la mia forma generale con le espressioni multiriga è ...

if (   (   (expr1 == expr2)
        || (expr3 == expr4)
        || (expr5 == expr6)
       )
    && (   (expr7 == expr8)
        || (expr9 == expra)
       )
   )
{
  blah;
}

Punti chiave ...

  • I parens vicini si allineano verticalmente con gli parentesi aperti, come con le parentesi graffe.
  • Le espressioni secondarie che rientrano in una riga sono all'interno di una riga e sono allineate verticalmente a sinistra. Dove aiuta la leggibilità, anche gli operatori infissi all'interno di quelle parti a linea singola sono allineati verticalmente.
  • Le parentesi graffe di chiusura creano naturalmente linee quasi vuote, contribuendo a raggruppare visivamente le cose.

A volte, formattare + e * o altri operatori come questo. Parecchie espressioni complesse prendono una forma di somma di prodotto o di somma di prodotto (che può riferirsi a "somme" e "prodotti" booleani), quindi è probabilmente abbastanza comune che valga la pena di uno stile coerente.

Stai attento con questo, però. Spesso è meglio rifattorizzare (spostare parti dell'espressione in una funzione, o calcolare e memorizzare parti intermedie in una variabile) piuttosto che usare la rientranza per provare a rendere più leggibile l'espressione di un sovracorpore.

Se preferisci impilare i parenti ravvicinati sul lato destro, non lo odio , ma suppongo che non sia troppo male. Preso troppo lontano, corri il rischio che un errore possa lasciare la rientranza travisando ciò che fanno le parentesi, però.

if (   (   (expr1 == expr2)
        || (expr3 == expr4)
        || (expr5 == expr6))

    && (   (expr7 == expr8)
        || (expr9 == expra)))
{
  blah;
}
    
risposta data 17.06.2011 - 02:55
fonte
1

link

Sono d'accordo con la risposta di JohnFx e con quella di Lacrymology. Creerei un sacco di funzioni (preferibilmente statiche) che realizzino piccoli obiettivi e poi li creiamo in modo intelligente.

Quindi, che ne dici di qualcosa del genere? Nota, questa non è la soluzione perfetta, ma funziona. Ci sono modi per ripulirlo ulteriormente, ma sono necessarie informazioni più specifiche. Nota: questo codice dovrebbe essere eseguito altrettanto velocemente, perché il compilatore è intelligente.

// Currently based on members or global vars
// (which is often a bad idea too)
function doSomethingCondirionally()
{
  if (k.isSomething() || m > n)
  {
    doSomething();
    return;
  }

  // Else ... 
  if (x != y) return;
  if (a == b) return;
  if (!p.isGood()) return;

  // Final, positive check
  if (i + u == b || q >= a)
  {
    doSomething();
  }
}
    
risposta data 17.06.2011 - 01:22
fonte
1

Per quello che vale, sono rimasto sorpreso nel vedere che il tuo esempio assomiglia molto ai complicati predicati che ho scritto. Sono d'accordo con gli altri sul fatto che un predicato complicato non è il massimo per la manutenibilità o la leggibilità, ma a volte vengono fuori.

Consentitemi di sottolineare che questa parte è stata corretta: && a != b MAI collocato il connettore logico alla fine di una riga, è troppo facile non vederlo visivamente. Un altro posto in cui non dovresti MAI mettere un operatore alla fine della linea è in concatenazione di stringhe, in lingue con un operatore del genere.

Fai questo:

String a = b
   + "something"
   + c
   ;

Non farlo:

String a = b +
   "something" +
   c;
    
risposta data 17.06.2011 - 02:03
fonte
0

Se il condizionale è così complicato, di solito è un'indicazione che dovrebbe essere suddiviso in parti. Forse una clausola può essere assegnata a una variabile intermedia. Forse una clausola può essere trasformata in un metodo di supporto. Generalmente preferisco non avere così tanti ands e or in una sola riga.

    
risposta data 17.06.2011 - 03:06
fonte
0

È possibile suddividere il codice in più istruzioni, semplificando la comprensione. Ma un vero ninja farebbe qualcosa del genere. : -)

if
(
    (
        x == y
    &&
        a != b
    &&
        p.isGood()
    &&
        (
            i + u == b
        ||
            q >= a
        )
    )
||
    k.isSomething()
||
    m > n
)
{
    doSomething();
}
    
risposta data 17.06.2011 - 03:17
fonte

Leggi altre domande sui tag