Java – Abstract Methods vs Instance Variables for Reusable Objects

abstract classabstractionArchitecturecode-reusejava

I have quite a bit of Java code that I'm re-working to be re-used. The problem is that there are many pieces that are project specific so there are ends up being a higher level of coupling between the application project and the code base project.

Compare to following situations where we use a class that implements the use of abstract methods to get the resources out of the child class, and one where we simply declare instance variables.

Abstract methods:

public abstract class SuperBaseClass {

    public abstract int getNumberOne();
    public abstract String getStringOne();
    public abstract String getStringTwo();

    public printStuff() {
        Log.i("IntAndTwoStrings", String.format("%i %s and %s",
                            getNumberOne(), getStringOne(), getStringTwo()));
    }

}

public class ReusedAppClass extends SuperBaseClass {

    public int getNumberOne() {
        return 1;
    }
    public String getStringOne() {
        return "String1";
    }
    public String getStringTwo() {
        return "String2";
    }

    public ReusedAppClass() {
        printStuff();
    }

}

Instance variables:

public class SuperBaseClass {

    protected int numberOne;
    protected String stringOne;
    protected String stringTwo;

    public printStuff() {
        //Possibly throw RuntimeExceptions if the app didnt set these
        Log.i("IntAndTwoStrings", String.format("%i %s and %s",
                            numberOne, stringOne, stringTwo));
    }

}

public class ReusedAppClass extends SuperBaseClass {

    public ReusedAppClass() {
        numberOne = 1;
        stringOne = "String1";
        stringTwo = "String2";
        printStuff();
    }

}

Is there a trade-off? Is the abstract method situation overkill, or is this what abstract classes were created for?

Best Answer

I think the abstract methods are the better choice. If the implementation of these properties is not something you want the sub-classes to worry about, you may even want the base class to be responsible for it i.e. use private fields in the base class with public accessors and protected mutators:

public class SuperBaseClass {

    private int numberOne;
    private String stringOne;
    private String stringTwo;

    public int getNumberOne() { return numberOne; }
    public String getStringOne() { return stringOne; }
    public String getStringTwo() { return stringTwo; }

    protected void setNumberOne(String numberOne) { this.numberOne = numberOne; }
    protected void setStringOne(String stringOne) { this.stringOne = stringOne; }
    protected void setStringTwo(String stringTwo) { this.stringTwo = stringTwo; }

    public printStuff() {
        Log.i("IntAndTwoStrings", String.format("%i %s and %s", getNumberOne(), getStringOne(), getStringTwo()));
    }
}

This kind of approach provides strong encapsulation i.e. the amount of code that can directly modify your fields is minimized.