5

I have the follow classes:

public abstract class MyAbstractClass {
     protected int x;
     protected int number;
     public MyAbstractClass(int x) {
         this.x = x;
         this.number = this.generateNumber();
     }
     public abstract int generateNumber(); // This class is called in the super constructor and elsewhere
}
public class MySubClass extends MyAbstractClass {
     private int y;
     public MySubClass(int x, int y) {
          super(x);
          this.y = y;
     }
     @Override
     public int generateNumber() {
         return this.x + this.y; // this.y has not been initialized!
     }
}

My issue is that MySubClass's y property has to be initialized before the super constructor is run, because a method using y is run in the super constructor. I am aware that this may not be possible even with some sneaky workaround, but I am yet to find an alternative solution.

Also please keep in mind that I will have many more derived classes, with different values being passed into their constructors.

4
  • 1
    Yes, you found a fundamental problem with this aproach. Yes, you should definitely look for an alternative solution. This can mean that you need to design your entire class hierarchy differently, or perhaps you can draw out the problematic part of the construction into some kind of factory. Commented Sep 29, 2020 at 5:40
  • @Hullk That question does describe my specific issue, but I didn't see any suggestions or workaround there. My goal right now is to find another solution that can do something similar. Commented Sep 29, 2020 at 5:44
  • There are several ways to handle this. One way is to separate the calculation of the field values to be used (can be done by a factory) and construction (done by constructor). Construction focusses on enforcing constraints (the classes invariants), without doing too much work itself. Commented Sep 29, 2020 at 5:48
  • It currently seems like a factory method is the best way to go for my problem, but please let me know if you have any other solutions. Commented Sep 29, 2020 at 6:24

1 Answer 1

4

You can defer the number calculation until it is needed.

public abstract class MyAbstractClass {
    protected int x;
    protected Integer number;

    public MyAbstractClass(int x) {
        this.x = x;
    }

    public int getNumber() {
        if (number == null) {
            number = generateNumber();
        }
        return number.intValue();
    }

    protected abstract int generateNumber(); 
}
Sign up to request clarification or add additional context in comments.

5 Comments

This is a great solution, but I may have been unclear in my question - the number has to be generated in the constructor, just because of how my program is built. It will need to use that value later on in the super constructor.
@klo then it should be calculated before the constructor call. You can also pass the calculation strategy as a parameter to the constructor (depending on how complex it is, as an object of a custom class or as a function interface), instead of having it as an overridable method (along the lines of the principle "prefer composition over inheritance")
@Hulk I can't pass the calculation as a function interface/lambda because it uses properties that would only exist in the subclass.
@klo you can still pass a lambda, it just has to accept a parameter
Well the lambda type wouldn't be specific, seeing as depending on the derived class, the properties it needs change.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.