Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make complex conditions look nice and save the number of statements?

In my java application I have a huge set of conditions which decides just one action. My question is how to make it look nice (I use NetBeans so I'd prefer solution that will not be broken by its code formatting function). I'd also like to have there as low amount of if/else statements as possible, because I think it will make it faster.

My original code was a mess, so I made an action diagram:complex action diagram full of conditions. Take a copy if you want to play with it. Please keep in mind that the diagram is not perfect as to UML syntax, partly because I made it using google docs.

This is the code:

if (!config.get("checkForSpecials") || event.isNotSpecial()) {
    if (config.get("filterMode").equals("blacklist")) {
        if (!itemFilter.contains(event.getItem().getName())) {
            item.process();
        }
    } else if (config.get("filterMode").equals("whitelist")) {
        if (itemFilter.contains(event.getItem().getName())) {
            item.process();
        }
    } else {
        item.process();
    }
}

There are two things I don't like about it - the conditions are not too clear (especially when I unfold full method names and config strings), and the fact that the process method call is there three times.

like image 450
Amunak Avatar asked Jan 10 '13 20:01

Amunak


2 Answers

Factoring booleans out and caching return values from method calls can help clarify code.

In addition, plotting all the outcomes on a logic table can help. I use this tool to help.

With the linked tool:

A: config.get("filterMode").equals("blacklist")
B: config.get("filterMode").equals("whitelist")
C: filterContainsName (see below)

The tool churns out:

(!A && !B) || (!A && C) || (A && !C)

Which leads to the code below (with a small tweak that replaces (!A && C) with (B && C)):

boolean filterContainsName = itemFilter.contains(event.getItem().getName());
boolean useBlacklist       = config.get("filterMode").equals("blacklist");
boolean useWhitelist       = config.get("filterMode").equals("whitelist");

if (!config.get("safeMode") || event.isSafe()) {
    if((!useBlackList && !useWhiteList) ||
       ( useWhiteList &&  filterContainsName) ||
       ( useBlackList && !filterContainsName)) {
        item.process();
    }
}
like image 171
Dancrumb Avatar answered Sep 18 '22 05:09

Dancrumb


Use maps. The key of the map is the condition/case, the value is a single method class/anonymouse interface that contains the logic for that condition. Whenever you encounter a certain condition/case, you simply do a lookup in the map and execute the related function. This way you can even split up your logic-by-condition into seperate classes (if needed for sake of code beauty). As an added bonus you'll probably gain a performance bonus when the # of conditions > 10.

like image 33
Zubzub Avatar answered Sep 22 '22 05:09

Zubzub