Skip to content Skip to sidebar Skip to footer

Improving Legibility On Conditional Statement

I am building a HTTP server for my android device. I am using a lot of IF-ELSE statements to handle differnt requests. As I will be sharing my code with other people for later use,

Solution 1:

As Luiggi Mendoza stated, this is a follow up of a previous question...

If you are using Java 7, you can use a switch-case statement for strings

//month is a Stringswitch (month.toLowerCase()) {
        case"january":
            monthNumber = 1;
            break;
          //partsleft out for sake of brevity ..default: 
            monthNumber = 0;
            break;
    }

(excerpt from the Oracle Java Tutorials, referenced above.)

Refactoring

However, this huge if-else is just part of the problem. As this seems to be a structure growing over time, I'd recommend a thorough refactoring, and using what seems to me is a Strategy pattern. You should:

Formulate an interface which covers the boundaries for all the use cases:

interfaceMyStrategy {
  voidexecute(MyInputContext input, MyOutputContext output);
}

(using a void method with MyInputContext and MyOutputContext are just one approach, this is just an example, but to handle requests that have responses, this makes sense, just like how Servlets work)

Refactor the content of the big IF-ELSE statement into instances of this interface (these will be the strategies):

//VERY simplified...classReadProfileStrategyimplementsMyStrategy {
  voidexecute(MyInputContext input, MyOutputContext output) {
    //do the stuff that was in the if-else block in the "readProfile" part
  }
}

//... at the branching part:MyInputContext input; //build this hereMyOutputContext output; //build this hereswitch (purpose) {
    case"readProfile":
         // no need to always instantiate this, it should be stateless...newReadProfileStrategy().execute();
         break;
    //... left out for sake of brevity
}

Refactoring step 2

If this is done, you can add the string IDs to the interface, and the instances themselves, and get rid of the if-else or switch statement altogether, you could create a Map populated even through an IOC container (like), to be up to date, and completely flexible.

classReadProfileStrategyimplementsMyStrategy {
  StringgetID() {
      return"readProfile";
  }

  voidexecute(MyInputContext input, MyOutputContext output) {
    //do the stuff that was in the if-else block in the "readProfile" part
  }
}

In the class when requests are processed

privatefinal Map<String, MyStrategy> strategyMap; //fill the map using your favorite approach, like using Spring application context, using the getCode() to provide the key of the map

In the processing logic:

MyStrategy strategy = strategyMap.get(purpose);
if(strategy!=null) {
    strategy.execute();
}
else {
    //handle error here
}

Solution 2:

This may be out of scope, but just an observation

try using

if("readProfile".equals(purpose){} instead of

if(purpose.equals("readProfile"){}.

It will help to avoid null pinter exception

Solution 3:

Enums can help - you can also add functionality to them.

publicvoidtest(String purpose) {
  if (purpose.equals("readProfile")) {
    // Read.
  } elseif (purpose.equals("writeProfile")) {
    // Write.
  }
}

enumPurpose {
  readProfile {
    @OverridevoiddoIt() {
      // Read.
    }
  },
  writeProfile {
    @OverridevoiddoIt() {
      // Write.
    }
  };

  abstractvoiddoIt();

}
publicvoidtest2(String purpose) {
  Purpose.valueOf(purpose).doIt();
}

Solution 4:

You can try using some kind of Action-Interface with implementations for each block and preload a map with concrete Implementations of this action.

interfaceAction {
    voidexecute();
}

Map<String, Action> actions = new HashMap<>();
actions.put("readProfile", new Action() { ... });
actions.put("writeProfile", new Action() { ... });

actionMap.get(purpose).execute();    

That will lower your cyclomatic complexity as well. Of course you should preload the map only once.

Solution 5:

Well, If it makes sense to separate code inside if-else condition to another class, perhaps use Factory pattern. Also make all separated classes implement common interface (eg: MyActivity.class) with a method such as execute().

Factory decides what object (ReadProfile.class, WriteProfile.class etc.) has to be created based on the string you pass and then call execute() method.

MyActivityobj= MyFactory.createMyActivity(String)
obj.execute(...);

Post a Comment for "Improving Legibility On Conditional Statement"