Search code examples
javadesign-patternsrefactoring

How to reduce the number of variables in the signature of method in child class? Java refactoring


I have an abstract class A which does the main work, and also there are classes B and C which extend class A and implements the method doTheFinalMove().

public abstract class A {

    public Object aMethod() {
        Integer var1 = calculateVar1();
        String var2 = calculateVar2();
        Boolean var3 = calculateVar3();
        Object var4 = calculateVar4();
        Object var5 = calculateVar5();

        return doTheFinalMove(var1,
                var2,
                var3,
                var4,
                var5
        );
    }

    protected abstract Object doTheFinalMove(Integer var1,
                                             String var2,
                                             Boolean var3,
                                             Object var4,
                                             Object var5);

}

public class B extends A {

    @Override
    protected Object doTheFinalMove(Integer var1,
                                    String var2,
                                    Boolean var3,
                                    Object var4,
                                    Object var5) {
        return doMyStaff(
                var1,
                var2,
                var3,
                var4,
                var5);
    }
}

public class C extends A {

    @Override
    protected Object doTheFinalMove(Integer var1,
                                    String var2,
                                    Boolean var3,
                                    Object var4,
                                    Object var5) {
        return doMyStaff(var1, var2);
    }
}

So, class C unlike class B needs only two of the five variables to do its job, but in order to keep the inheritance of the class A, I should use all the five variables in the signature of doTheFinalMove() in A and C classes. I would like to refactor this code in the way that class C keep in its signature only those variables that it really needs (var1 and var2). I want to avoid using Object... args stuff, so I thought about wrapping these variables into an Object(I mean some inheritance like BasicParams and ExtendedParams) and then using an AbstractFactory or smth like that, but I don't know how to do it properly. I would be grateful for any advice.


Solution

  • As suggested you can overload many form of your method in the abstract. You call from the more specific to the less specific in the abstract, then only override the needed method.

    public abstract class A {
    
        public Object aMethod() {
            Integer var1 = calculateVar1();
            String var2 = calculateVar2();
            Boolean var3 = calculateVar3();
            Object var4 = calculateVar4();
            Object var5 = calculateVar5();
    
            return doTheFinalMove(var1,
                    var2,
                    var3,
                    var4,
                    var5
            );
        }    
    
        protected Object doTheFinalMove(Integer var1,
                                             String var2,
                                             Boolean var3,
                                             Object var4,
                                             Object var5){
             return doTheFinalMove(var1,var2);
        }
    
        protected Object doTheFinalMove(Integer var1,
                                             String var2){
            throw new UnsupportedOperationException("You have to override one of the doTheFinalMove method");
        }
    
    
    }
    
    
    public class B extends A {
    
        @Override
        protected Object doTheFinalMove(Integer var1,
                                    String var2,
                                    Boolean var3,
                                    Object var4,
                                    Object var5) {
        return doMyStaff(
                var1,
                var2,
                var3,
                var4,
                var5);
         }
    }
    
    public class C extends A {
    
        @Override
        protected Object doTheFinalMove(Integer var1,
                                    String var2) {
            return doMyStaff(var1, var2);
        }
    }
    

    If you want to avoid the exception and force the implementation of the method by the compiler, you may add Abstract levels, but the complexity augmentation is only usefull if you have more than 1 implementation imho (i.e. more than only B and C)

    Variant with 1 more abstraction:

    public abstract class A {
    
        public Object aMethod() {
            Integer var1 = calculateVar1();
            String var2 = calculateVar2();
            Boolean var3 = calculateVar3();
            Object var4 = calculateVar4();
            Object var5 = calculateVar5();
    
            return doTheFinalMove(var1,
                    var2,
                    var3,
                    var4,
                    var5
            );
        }    
    
        protected Object doTheFinalMove(Integer var1,
                                             String var2,
                                             Boolean var3,
                                             Object var4,
                                             Object var5);
    
    
    
    }
    

    public abstract class A2 extends A {

        protected Object doTheFinalMove(Integer var1,
                                             String var2,
                                             Boolean var3,
                                             Object var4,
                                             Object var5){
             return doTheFinalMove(var1,var2);
        }
    
        protected abstract Object doTheFinalMove(Integer var1,
                                             String var2);
    
    }
    // Then C should extends A2 instead of A