Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design patterns that can replace if statements

Our application is getting complex, it has mainly 3 flow and have to process based on one of the 3 type. Many of these functionalities overlap each other.

So currently code is fully of if-else statements, it is all messed up and not organised. How to make a pattern so that 3 flows are clearly separated from each other but making use of power of re-usability.

Please provide some thoughts, this is a MVC application, where we need to produce and consume web servicees using jaxb technology.

May be you can view the application as a single object as input on which different strategies needs to be implemented based on runtime value.

like image 598
Valath Avatar asked Jul 23 '15 07:07

Valath


People also ask

How do you avoid if-else statements?

Avoid using nested if-else statements. Keep the code linear and straightforward. Utilize creating functions/methods. Compare it when we try to use an if-else statement that is nested and that does not utilize the power of the return statement, We get this (Code 1.4).

How do you remove if-else condition in factory pattern?

Object Oriented Language has very powerful feature of Polymorphism, it is used to remove if/else or switch case in code. Code without condition is easy to read. There are some places where you have to put them and one of such example is Factory/ServiceProvider class.


2 Answers

You did not specify what your if-else statements are doing. Say they filtering depending on some value.

If I understand your question correctly, you want to look at Factory Pattern.

This is a clean approach, easy to maintain and produces readable code. Adding or removing a Filter is also easy, Just remove the class and remove it from FilterFactory hashmap.

Create an Interface : Filter

 public interface Filter {
    void Filter();
 }

Create a Factory which returns correct Filter according to your value. Instead of your if-else now you can just use the following :

  Filter filter = FilterFactory.getFilter(value);
  filter.filter();

One common way to write FilterFactory is using a HashMap inside it.

public class FilterFactory{
   static HashMap<Integer, Filter> filterMap;
   static{
       filterMap = new HashMap<>();
       filterMap.put(0,new Filter0());
       ...
   }
   // this function will change depending on your needs
   public Filter getFilter(int value){
       return filterMap.get(value);
   }

}

Create your three(in your case) Filters like this: (With meaningful names though)

public class Filter0 implements Filter {

    public void filter(){
      //do something
    }
}

NOTE: As you want to reuse some methods, create a FilterUtility class and make all your filters extend this class so that you can use all the functions without rewriting them.

like image 193
Karthik Avatar answered Oct 08 '22 20:10

Karthik


Your question is very broad and almost impossible to answer without some description or overview of the structure of your application. However, I've been in a similar situation and this is the approach I took:

Replace conditions with Polymorphism where possible

it has mainly 3 flow and have to process based on this one of the 3 type. Many of these functionalities overlap each other.

You say your project has 3 main flows and that much of the code overlaps each other. This sounds to me like a strategy pattern:

You declare an interface that defines the tasks performed by a Flow.

public interface Flow{
   public Data getData();
   public Error validateData();
   public void saveData();
   public Error gotoNextStep();
}

You create an abstract class that provides implementation that is common to all 3 flows. (methods in this abstract class don't have to be final, but you definitely want to consider it carefully.)

public abstract class AbstractFlow{

   private FlowManager flowManager

   public AbstractFlow(FlowManager fm){
    flowManager = fm;
   }

   public final void saveData(){
       Data data = getData();
       saveDataAsXMl(data);
   }

   public final Error gotoNextStep(){

      Error error = validateData();
      if(error != null){
         return error;
      }

      saveData();
      fm.gotoNextStep();
      return null;
   }
}

Finally, you create 3 concrete classes that extend from the abstract class and define concrete implementation for the given flow.

public class BankDetailsFlow extends AbstractFlow{

   public BankDetailsData getData(){
     BankDetailsData data = new BankDetailsData();
     data.setSwiftCode(/*get swift code somehow*/);
     return data;
   }

   public Error validateData(){
      BankDetailsData data = getData();
      return validate(data);
   }

   public void onFormSubmitted(){
      Error error = gotoNextStep();
      if(error != null){
        handleError(error);
      }
   }
}
like image 41
W.K.S Avatar answered Oct 08 '22 21:10

W.K.S