0

I try to design one translation server. There have one POJO class (RootClass)in my local systems. and there also have remote system to sent Remote object(RemoteClass) to my system. The responsibility of this service is translate Remote class to Root class. The issue is that: There so many types. e.g. more than 200 types. I need write huge if-else to do this translation:

I list some pseudocode code to describe this question.

public class RootClass  {
    public String type;
    public String attr1;
    public String attr2;
    public String attr3;
    public String attr4;
}


public class RemoteClass  {
    public String type;
    public String attr1;
    public String attr2;
    public String attr3;
}


public class Translator{

     public RootClass translate(RemoteClass remote) {
         RootClass root = new RootClass();

         if ("a".equals(remote.type ))  {
             root.type = "veryGood";
             if ("one".equals(remote.attr1)) {
                  root.attr2 = "true";
             }
             if ("two".equals(remote.attr1)) {
                 root.attr3 = "true";
             }
             if ("1".equals(remote.attr1) && "2".equals(remote.attr2) ) {
                 root.attr4 ="good";
             }

         } else if ("b".equals(remote.type)) {
             root.type = "good";
             if ("one".equals(remote.attr1)) {
                 root.attr2 = "1";
             } else if ("two".equals(remote.attr1)) {
                 root.attr2 ="2";
             }

         }  else if ("c".equals(remote.type)) {
             root.type = "good";
             if (remote.attr2.indexOf(":") > 0 )  {
                 String[] strArray = remote.attr2.split(":");
                 root.attr2=strArray[0];
                 root.attr3=strArray[1];
             }

         }

     }
}

The 2 object describe 1 thing with totally difference structure. Root class is kernel of our system and impossible to strut and we also think this Root class is very suitable for local system. and for Remote class is come from 3-rd party systems which we have no permission to change. So this translation is become very hard.

What I plan to remove is create more than 200 adopter for translation: e.g:

public class adopterA implements RootAdoper {
public RootClass translate(RemoteClass remote) {
    RootClass root = new RootClass();
    root.type="veryGood";
    if ("one".equals(remote.attr1)) {
        root.attr2 = "true";
    }
    if ("two".equals(remote.attr1)) {
        root.attr3 = "true";
    }
    if ("1".equals(remote.attr1) && "2".equals(remote.attr2) ) {
        root.attr4 ="good";
    }
}

}

And put all of those into HasMap

Map<String, RootAdoper> map = new HashMap<String, RootAdoper>();

But still have 200 small class to wrap if/else, Is any good pattern or design to solve this complex issue? Thanks in advance.

Bensson
  • 4,509
  • 4
  • 19
  • 24

1 Answers1

1

What is the key in your map? if the key is the Remote.type then you can just do

rootClass = map.get(remote.type).translate(remote);

Which does get rid of the if/else if blocks. Just be sure to handle unknown/ untranslated regions or have a NullObject that doesn't translate or performs a default translation.

The technical name for this from the book Refactoring to Patterns is called "Replace Conditional Dispatcher with Command"

You still have to populate the map though. Perhaps one way to do this is to make all the RootAdoper interface an enum and all implementations the types in the enum. You can also add a new method to the enum to get the Remote.Type that each value can translate.

enum RootAdoper{

     A{
        @Overide
        public RootClass translate(RemoteClass remote){
           //...
        }

        @Override
        public String getTypeToTranslate(){  
            return "A";
        }
     },
     ... // other types listed here similarly
     ;

  abstract RootClass translate(RemoteClass remote); 

  abstract String getTypeToTranslate();
}

Then you can populate the Map like this

 Map<String, RootAdoper> map = new HashMap<String, RootAdoper>();

 for(RootAdoper adoper : RootAdoper.values(){
        map.put(adoper.getTypeToTranslate(), adoper);
 }
dkatzel
  • 31,188
  • 3
  • 63
  • 67
  • Thanks. That be better when use enum. Good idea. But this enum is still big. Is any way to make all of this in configuration? I usually got all of those information from Domain expert. I collect those information to excel and then I work on code. Is that possible to have all of this in configuration, that will be reduce a lot of work. I mean: A: VeryGood. B:good. this is easy to configure in DB or source code. but for other complex rule `(remote.attr2.indexOf(":"))` is very hard to do this way. You are very good at refactor, So can you give me suggestion on this. – Bensson Oct 17 '13 at 07:08
  • Coded up classes or dynamically generated by reading a DB or excel file are both good options. I would favor one over the other depending on how often the rules for translation change. If the rules will never change or change so infrequently that any change would require rewriting the code, I would say go for the method I describe above. You only have the pain of writing the code once and then it will just work. Reading DB or config/excel is more complicated because that requires one more translator to parse the configuration and you would still end up with lots of classes – dkatzel Oct 17 '13 at 14:19