javadesign-patternsmodelmdd

Design for translation layer


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.


Solution

  • 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);
     }