Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactoring a complicated if-condition

Can anyone suggest best way to avoid most if conditions? I have below code, I want avoid most of cases if conditions, how to do it ? any solution is great help;

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        } else {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        } else {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        }
    }
} else {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        } else {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        } else {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        }
    }
}
like image 885
kumar kasimala Avatar asked May 05 '10 10:05

kumar kasimala


People also ask

How do you refactor an if statement?

So, how do you refactor multiple nested if statements? The easiest possible way is to use guard clauses. A guard clause is an if statement that checks for a condition and favors early exit from the current method. If the condition is satisfied, the if block returns from the method.

Is it okay to nest if statements?

You can place or nest an If statement inside another If statement. When you nest If statements, you can check for a condition only when another condition is found to be true.


2 Answers

How to go about this... Let's extract a couple of methods, so we can better see the logic.

private void a() {
    entry2.setDebit(adjustment.total);
    entry2.setCredit(0d);
}
private void b() {
    entry2.setCredit(adjustment.total);
    entry2.setDebit(0d);
}

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            a();
        } else {
            b();
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            b();
        } else {
            a();
        }
    }
} else {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            b();
        } else {
            a();
    }
} else {
    if (adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
}

So now, looking at it, that first block

if (adjustment.increaseVATLine) {
    if (adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
} else {
    if (adjustment.vatItem.isSalesType) {
        b();
    } else {
        a();
    }
}

just amounts to doing a() if adjustment.increaseVATLine has the same value as adjustment.vatItem.isSalesType, b() otherwise. So we can reduce it:

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
} else {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            b();
        } else {
            a();
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            a();
        } else {
            b();
        }
    }
}

And the remaining block is the same, just reversing a() and b():

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
} else {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        b();
    } else {
        a();
    }
}

So we begin to see the logic. If it's an increase, and the increaseVATLine matches the isSalesType, then we debit, otherwise credit, but if it's a decrease, then we credit only if they don't match. What's a good way of expressing this? Well, for one, name a() and b() smarter - now that we can see what they're doing

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        debitEntry();
    } else {
        creditEntry();
    }
} else {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        creditEntry();
    } else {
        debitEntry();
    }
}

And now it's a little clearer still. Debit the account when it's an increase account and an increase VAT line, and a sales type, or when it's a decrease and either it's a decrease VAT line OR it's a sales type, but not both. Does this truth table help? First column is adjustmentAmount.isIncrease; second is adjustment.increaseVATLine; third is adjustment.vatItem.isSalesType. Fourth column is D for debit, C for credit; in parentheses are the number of TRUE values among the flags.

TTT -> D (3) 
TFF -> D (1) 
TTF -> C (2)
TFT -> C (2) 
FTT -> C (2) 
FFF -> C (0)
FTF -> D (1) 
FFT -> D (1)

Now you can see why @Xavier Ho's solution works; the odd totals are all debits, the even ones all credits.

This is just one exploratory path; I hope it's helpful.

like image 115
Carl Manaster Avatar answered Oct 16 '22 11:10

Carl Manaster


I haven't thoroughly verified the logic, but this is the basic idea:

amt = adjustment.total
if (adjustment.adjustmentAccount.isIncrease
    ^ adjustment.increaseVATLine
    ^ adjustment.vatItem.isSalesType)
{
    amt = -amt;
}

entry2.setCredit(amt > 0 ? amt : 0);
entry2.setDebit(amt < 0 ? -amt : 0);

I should note that this logic is slightly different in that it correctly handles a negative value of adjustment.total, whereas the original seems to assume (perhaps correctly) that the value will always be non-negative.

like image 31
Marcelo Cantos Avatar answered Oct 16 '22 11:10

Marcelo Cantos