samedi 8 juin 2019

Java Design Problem For Default Services and Inheritance

class Input{}
class Output{}
class Mid {}
class RInput extends  Input{}
class ROutput extends Output{}
class RMid extends Mid {}

Consider the following BASE classes as my POJOs, which contain Data, RInput can have fields over and above Input, same analogy follows elsewhere.

Now Consider the Services using these classes.

class RIS extends  IS<RInput>{
    @Override
    Output call(RInput i) {

        Mid mid = m1(i);
        return resp(mid);

    }

    @Override
    public Output resp(Mid a) {
        return super.resp(a);
    }


}
class IS<T extends Input>{

    Output call(T i){
        Mid a=m1(i);
        return resp(a);
    }

    public Output resp(Mid a) {
        return new Output();
    }

    public Mid m1(Input i) {
        return new Mid();
    }


}

Please note that IS class has 3 methods, any one of which can be overridable by RIS. So, IS is the default implementation of RIS service, it may be that RIS does not need its own behaviour in any of the methods, and hence, it will be an empty class.

However, RIS can choose to override any/all of the methods of IS. The special thing to notice is the call() method, which decides the order of execution of other methods/steps. This is the method which will be called from outside on an instance of RIS.

The Problem: Try to design a clean code which gives me freedom to use any of the 6 BASE classes in RIS, depending on the situation. The usage of a class must guarantee that the new implementation adds extra functionality on the existing default implementation. So if by chance, Mid{}/RMid{} classes looks like :

Mid{ int a,b,c;}
RMid extends Mid{ int d;}

the overridden method of RMid should have Default functionality as well as RMid functionality. Constraints: Avoid mapping from Mid object to RMid Object. I do not want to rework creating a lot of mapping objects in code(because I will be having a lot of methods - m1() ,m2(), m3(), with input output chains) like-

public RMid m1(Input i) {
        return convertToRMid(super.m1(i));// Do not want to write convert methods
    }

Also compile time will fail if I do not choose generics for resp(RMid rmid).

@Override
    public Output resp(RMid a) {// No Generics used here, compile time fails
        return super.resp(a);
    }

I have tried generics, but they do not promise clean easy to understand code. Clarity is important as this code will be read by many people who will be creating tons of services like RIS. And they will copy the style in which I write RIS.

I have tried an approach where I create an object RMid in RIS , and keep passing it to superMethods, but it uses typecasting and checks in the Default implementation.

I tried a factory approach as well, where I used reflection to create objects , but it was also not a very simple understandable approach.

I tried Decorators, but they are good at changing state of an existing member, not adding an inherited member(I may be wrong here).

Stuck in this problem for a week now, a quick solution will really help. Thanks in advance. I know this is a hard problem because I gave it to a group of highly experienced individuals, none of whom could help me with a solution.

Note: I believe if you are doing too many typecasts, or writing too many convert methods, you have not designed your code properly. Not sure if thats the truth.

Aucun commentaire:

Enregistrer un commentaire