One "truely object oriented" answer would be to define an interface for "Rule" (with condition() and action() methods), create 3 implementations, stuff them into a collection, and then just iterate through them generically as in:
List<Rule> rules = .... ; // your 3 rules initialized here somehow
for(Rule r : rules) {
if(r.condition()) {
r.action();
}
}
This makes a lot more sense if you have 300 rules/conditions rather than just 3.
In Java8, you may want to do this instead, if the rules are CPU-intensive:
rules.parallelStream().filter(Rule::condition).forEach(Rule::action);
Answer from Alex R on Stack OverflowOne "truely object oriented" answer would be to define an interface for "Rule" (with condition() and action() methods), create 3 implementations, stuff them into a collection, and then just iterate through them generically as in:
List<Rule> rules = .... ; // your 3 rules initialized here somehow
for(Rule r : rules) {
if(r.condition()) {
r.action();
}
}
This makes a lot more sense if you have 300 rules/conditions rather than just 3.
In Java8, you may want to do this instead, if the rules are CPU-intensive:
rules.parallelStream().filter(Rule::condition).forEach(Rule::action);
The short answer is yes.
There are a few time you can avoid using if for conditional evluation and branching all together. And they have moments of appropriateness.
- Polymorphism, when behavior is dependent on the initial values
Referrenced Assignment, when you know the possible initial values and they have 1 to 1 correlation with the return values. Lists are better than arrays for this, but...
// Example: if (a==1) { b=2; } if (a==2) { b=17; } // Becomes int fx(2); // our array of answers fx[0] = 2; fx[1] = 17; b = fx[ a - 1 ];Referrenced Branching, when you know the possible initial values and they have 1 to 1 correlation with the function/branch to use. (example not Java)
// Example: if (a==1) { doSomething1(); } if (a==2) { doSomething2(); } // Becomes function * fx(2); // our array or better still, list of functions fx[0] = &doSomething1; fx[1] = &doSomething2; `fx a - 1 ; `Direct boolean assignment.
We hate:
if (thisCondition == true) { b = true; } else { b = false; }Should be:
b = thisCondition;
java - Alternative of if-else and switch statements - Stack Overflow
java - What alternatives are there for if else statements? - Stack Overflow
java - Quick alternative to lots of if statements - Stack Overflow
java - What is the better way to escape from too many if/else-if from the following code snippet? - Software Engineering Stack Exchange
If you can use JavaScript, you can use a object with functions:
function doSomething(i) {
var obj = {};
obj[12] = function () {
// order should be same
up();
left();
stop();
};
obj[304] = function () {
// order should be same
right();
up();
stop();
};
obj[962] = function () {
// order should be same
down();
left();
up();
stop();
};
// apparently we can't use any conditional statements
try {
obji;
} catch (e) {}
}
If only if and switch statements aren't allowed, replace all the if statements with the logical AND operator (&&):
function doSomething(i) {
(i == 12) && (
// order should be same
up(),
left(),
stop()
);
(i == 304) && (
// order should be same
right(),
up(),
stop()
);
(i == 962) && (
// order should be same
down(),
left(),
up(),
stop()
);
}
Here is a simple way to accomplish this in JavaScript:
function up() { console.log("up"); }
function down() { console.log("down"); }
function left() { console.log("left"); }
function right() { console.log("right"); }
function stop() { console.log("stop"); }
var fnmaps = {
12: [up, left, stop],
304: [right, up, stop],
962: [down, left, up, stop]
};
function doSomething(i) {
var fnmap = fnmaps[i] || [], j;
for (j = 0; j < fnmap.length; j++) {
fnmapj;
}
}
doSomething(12);
doSomething(304);
doSomething(962);
Functions can be added/ordered simply by editing the map variable.
Use a switch statement or a HashMap.
Switch statement: Readable, but compiles similarly (if not identically) to an if-else chain.
switch([USER_INPUT]) {
case 1:
System.out.println("TEST");
break;
case 2:
System.out.println("HELLO");
break;
// And so on.
}
Hash Map: Much more readable and simpler. This is preferred.
// Initialization.
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"TEST");
map.put(2,"HELLO");
// Printing.
String s = map.get(USER_INPUT);
if (s == null)
System.out.println("Key doesn't exist.");
System.out.println(s);
Use a HashMap, with key as Integer, and value as text.
System.out.println(myMap.get(USER_INPUT));
Where you have done myMap.put(1, "TEST"); etc, this keeps your code much OO.
the underlying bytecode of switch and if are very comparable, and personally don't see any advantage of switching to switch (unless you want fall through, which means don't include break statement).
Based on the previous answer, Java allows enums to have properties so you could define a strategy pattern, something like
public enum Action {
A ( () -> { //Lambda Sintax
// Do A
} ),
B ( () -> executeB() ), // Lambda with static method
C (new ExecutorC()) //External Class
public Action(Executor e)
this.executor = e;
}
//OPTIONAL DELEGATED METHOD
public foo execute() {
return executor.execute();
}
// Action Static Method
private static foo executeB(){
// Do B
}
}
Then your Executor (Strategy) would be
public interface Executor {
foo execute();
}
public class ExecutorC implements Executor {
public foo execute(){
// Do C
}
}
And all your if/else in your doPost method become something like
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String action = req.getParameter("action");
Action.valueOf(action).execute();
}
This way you could even use lambdas for the executors in the enums.
Instead of using reflection, use a dedicated interface.
ie instead of :
/**
* Still was not comfortable since i am doing un-necessary checks in one way or the other
* So tried with [reflection][1] by invoking the action methods
*/
Map<String, Method> methodMap = new HashMap<String, Method>();
methodMap.put("action1", SampleClass.class.getMethod("action1"));
methodMap.put("action2", SampleClass.class.getMethod("action2"));
methodMap.get(action).invoke(null);
Use
public interface ProcessAction{
public void process(...);
}
Implements each of them for each actions and then :
// as attribute
Map<String, ProcessAction> methodMap = new HashMap<String, ProcessAction>();
// now you can add to the map you can either hardcode them in an init function
methodMap.put("action1",action1Process);
// but if you want some more flexibility you should isolate the map in a class dedicated :
// let's say ActionMapper and add them on init :
public class Action1Manager{
private static class ProcessAction1 implements ProcessAction{...}
public Action1Manager(ActionMapper mapper){
mapper.addNewAction("action1", new ProcessAction1());
}
}
Of course this solution isn't the lighest, so you may not need to go up to that length.
To shorten multiple if-else statements you can use inline if:
((condition == value)?'expr1':'expr2')
expr1 executes when condition is true, else expr2 executes.
String parentFolder = "";
parentFolder = (((name.matches("birds"))?"birdPFUuid":
(name.matches("dogs"))?"dogsFUuid": // if "dogs" then set parent folder to "dogsFUid" else check code in line below
(name.matches("cats"))?"catsFUuid":
(name.matches("vehicles"))?"vehiclesFUuid":""
));
You can use a map data structure to map the parent folder UUID to the dataset name.
Map<String, String> uuidMap = new HashMap<>();
uuidMap.put("birds", birdPFUuid);
uuidMap.put("dogs", dogPFUuid);
uuidMap.put("cats", catPFUuid);
uuidMap.put("vehicles", vehiclesPFUuid);
public void check(String name){
String parentFolder = uuidMap.get(name);
}