4

I think this is a very common situation in web projects. Assume there is an entity such as:

//JAVA code
@Data
class Entity{

    private String a;
    private String aExt;

    private String b;
    private String bExt;

    private String c;
    private String cExt;

    ... something more ...
}

For some purpose, I need to get part of values from Entity according to a passed argument, like:

public ViewObject foo(Entity entity, String condition){

    ViewObject vo = new ViewObject();

    if("aRelated".equals(condition)){
        vo.setValue1(entity.getA());
        vo.setValue2(entity.getAExt());
    }
    else if("bRelated".equals(condition)){
        vo.setValue1(entity.getB());
        vo.setValue2(entity.getBExt());
    }
    else if(cRelated".equals(condition)){
        vo.setValue1(entity.getC());
        vo.setValue2(entity.getCExt());
    }
    ... else statement if there are other values ....

    return vo;
}

I know I can use switch-case statement to reduce some words in foo(), but there is no essential difference compared with if-else, especially when the Entity has many variables.

As a plain Example, foo() is only a view object builder, but my project is more complex which have many duplicated code with only different variable's name in each if-else statement.

How do I reduce the above duplicated code?

scott
  • 375
  • 2
  • 9

4 Answers4

4

You can try creating two hash maps:

// name these properly!
HashMap<String, Function<Entity, String>> valueMap = new HashMap<>();
HashMap<String, Function<Entity, String>> extMap = new HashMap<>();

Add these KVPs:

// valueMap
"aRelated" - Entity::getA
"bRelated" - Entity::getB
"cRelated" - Entity::getC

// extMap
"aRelated" - Entity::getAExt
"bRelated" - Entity::getBExt
"cRelated" - Entity::getCExt

Now, you can do this without an if statement:

vo.setValue1(valueMap.get(condition).apply(entity));
vo.setValue2(extMap.get(condition).apply(entity));
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • thanks, this looks more clear, and I just found [some way](https://stackoverflow.com/questions/8261075/adding-multiple-entries-to-a-hashmap-at-once-in-one-statement) to reduce code on adding KVPs. – scott May 04 '18 at 09:26
1

Another option would be to use reflection:

import java.lang.reflect.Method;
import java.lang.reflext.InvocationTargetException;

...

public ViewObject foo(Entity e, String c) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  String[] methodNames = { "get" + c.substring(0,1).toUpperCase(), "get" + c.substring(0,1).toUpperCase() + "Ext" }; 
  Method[] methods = { e.getClass().getDeclaredMethod(methodNames[0]), e.getClass().getDeclaredMethod(methodNames[1]) };
  ViewObject vo = new ViewObject();                                                                                                   

  vo.setValue1((String)methods[0].invoke(e));                                                                                         
  vo.setValue2((String)methods[1].invoke(e));                                                                                         

  return vo;                                                                                                                          
}

Although I have to admit I personally like the map approach of the other answers more, just showing more options.

tjanu
  • 172
  • 2
  • 11
0

Use of a Map would do the trick:

class EntityPart {
    String s;
    String sExt;
}

class Entity {
    Map<String,EntityPart> m = new HashMap<>();
    m.add("aRelated",new EntityPart());
    m.add("bRelated",new EntityPart());
    ....
}

public ViewObject foo(Entity entity, String condition) {
    ViewObject vo = new ViewObject();
    EntityPart ep = entity.m.get(condition);
    vo.setValue1(ep.s);
    vo.setValue2(ep.sExt);
    return vo;
}
Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0

Make Entity as enum instead of class.

public enum Entity {

    A("a", "aExt"), B("b", "bExt"), C("c", "cExt");

    private final String name;
    private final String text;

    private Entity(String name, String text) {
        this.name = name;
        this.text = text;
    }

    public String getName() {
        return name;
    }

    public String getText() {
        return text;
    }

    public static Entity fromString(String raw) {

        return LOOKUP.get(raw);
    }

    private static final Map<String, Entity> LOOKUP = new HashMap<>();

    static {

        for (Entity e : values()) {
            LOOKUP.put(e.getName(), e);
        }
    }
}

And modify your foo method as

public ViewObject foo(String condition){

    /*
     *  pass condition as "a", "b", "c" only not "aRelated", "bRelated", "cRelated"
     * 
     */
    ViewObject vo = new ViewObject();
    Entity e = Entity.fromString(condition); 
    if(null != e) {
        vo.setValue1(e.getName());
        vo.setValue2(e.getText());
    }
    return vo;
}
Hemant Patel
  • 3,160
  • 1
  • 20
  • 29