Home > Mobile >  how to avoid duplicate in the code using generics or Function classes
how to avoid duplicate in the code using generics or Function classes

Time:07-04

private <Y> void meth(
            MyObj ds, MultiValueMap<String, List> mvm, Class<Y> data) {

            

        if(data.isAssignableFrom(Employee.class)) {
            for (Employee rd : (List<Employee>) mvm.get(0).get(1)) {
               
                for (String cName : (List<String>) mvm.get(0).get(0)) {
                    ds.setCellValue((String)rd.getDataElement(cName));
                   
                }
               
            }
        }

        if(data.isAssignableFrom(Department.class)) {
            for (Department rd : (List<Department>) mvm.get(0).get(1)) {
               
                for (String cName : (List<String>) mvm.get(0).get(0)) {
                    ds.setCellValue((String)rd.getDataElement(cName));
                    
                }
               
            }
        }
        
        
        //some more similar if conditions as above
        
}

In above, I have like similar 10 if conditions, how to avoid duplicate code in above? Do I need to use any Java 8 Function classes as parameters to avoid duplicate code (or) have to use any extra generics code?

CodePudding user response:

So it looks like that what you need is inheritance and not generics. In your if condition you always cast and call the same method on the Object. So what you can do is e.g. define an interface looking something like this:

public interface MyInterface {
    String getDataElement(String name);
}

And implement it in your Employee, Department and other classes you have.


If the method always does the same you can use default or an abstract class to not always write the same:

public interface MyInterface {
    default String getDataElement(String name) {
        //do your thing
        return value;
   }
}
public abstract class MyAbstractClass {
    public String getDataElement(String name) {
        //do your thing
        return value;
   }
}

Now you can change your meth method to this:

private void meth(MyObj ds, MultiValueMap<String, List> mvm) {
    List<MyInterface> list = (List<MyInterface>) mvm.get(0).get(1));

    for (MyInterface rd : list) {
        List<String> cNames = (List<String>) mvm.get(0).get(0);
        for (String cName : cNames) {
            ds.setCellValue((String) rd.getDataElement(cName));
        }
    } 
}

CodePudding user response:

You can simplify this code using generics.

Here is one of your if blocks:

if (data.isAssignableFrom(Employee.class)) {
    for (Employee rd : (List<Employee>) mvm.get(0).get(1)) {
        for (String cName : (List<String>) mvm.get(0).get(0)) {
            ds.setCellValue((String) rd.getDataElement(cName));
        }
    }
}

A few things stand out:

  • It uses Employee - this is a "type"; generics can help here.
  • It uses Employee.class - this is a java.lang.Class; generics cannot help here, since types and classes are not the same thing.

Below is a new function which:

  • Uses generics to define <T> – this is the part right before void; so, T is not the return type, but the type of the method. It's screwy syntax, but it's correct and it works.
  • Requires a Class parameter "cls" - this is where the caller would pass in something like Employee.class. Remember, classes are not types – we can't get this class info from T, that's not how it works.
private static <T> void extracted(Map<String, List<?>> mvm, Class<?> data, Class<?> cls) {
    if (data.isAssignableFrom(cls)) {
        for (T rd : (List<T>) mvm.get(0).get(1)) {
            // do things
        }
    }
}

You can then call that new function like this, specifying a type in the function call – GenericsExample.<Employee>extracted(...) – as well as the class to use (Employee.class, Department.class). I filled in a few other things (dummy definition for mvm and data) in order to make the code valid.

public class GenericsExample {
    public static void main(String[] args) {
        Map<String, List<?>> mvm = new HashMap<>();
        Class<?> data = new Object().getClass();

        GenericsExample.<Employee>extracted(mvm, data, Employee.class);
        GenericsExample.<Department>extracted(mvm, data, Department.class);
    }
}

UPDATE: I've thought a bit more about the problem you're solving and the solution I provided. It feels like if you were to take a step back, there is probably a better overall solution than specifying a type T and a class. But, with the problem stated as it is, I'll leave this solution as it is, too.

  • Related