2

I have the following classes:

abstract class Parent
{
    private ClassDependentOnSize classDependentOnSize;

    public Parent ()
    {
        this.classDependentOnSize = new ClassDependentOnSize(size());
    }

    public abstract int size ();
}

class Child extends Parent
{
    private String DBSelection;
    private String[] DBSelectionArgs;

    public Child (String selection, String... selectionArgs)
    {
        super();
        this.DBSelection = selection;
        this.DBSelectionArgs = selectionArgs;
    }

    @Override
    public int size()
    {
        //FAILS because Parent calls size before DBSelectionArgs is initialized
        String temp = "";
        for(String str : DBSelectionArgs)
           temp += str;
        return temp.length;

        //This function basically does a calculation that should not be
        //done before hand. I have posted the exact method below.
    }
}

class ClassDependentOnSize 
{
    public ClassDependentOnSize(int size)
    {

    }
}

While this are not my exact class, this is the same problem. I have written this one to remove all the unnecessary code.

As you can see, the super class tries to call size () before the child is finished initializing to construct the class dependent on size. I am curious on how anyone has resolved this in the past. As I am sure everyone is aware, super() must be the first line in a child constructor. As I have laid these classes out, is this a bad design? I feel like this is a problem that must have happened before, but I can not find a solution.

EDIT: Here is the exact method. It uses for an Android application.

protected Cursor getCursor()
{
    if (songCursor == null)
    {
        songCursor = GET_SONGS_CURSOR(getContext(), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString(), selection, selectionArgs, selection);

        if (!songCursor.moveToFirst())
            Standard.Loge("|NewPlaylist.getCursor| Could not move to first.");
    }

    int count = songCursor.getCount();
    songCursor.close();
    return count;
}
Andrew No
  • 535
  • 6
  • 20

3 Answers3

1

A simple solution for your specific case is to pass the size as an argument to the parent constructor.

This of course assumes that your real problem has the same characteristics, namely that all the information needed by the base class constructor are available when calling the constructor.

Markus
  • 3,155
  • 2
  • 23
  • 33
  • Yes, but original poster says this is not his/her *exact* problem – ControlAltDel Apr 28 '16 at 18:11
  • ControlAltDel is correct, I am unable to determine the size beforehand as it is calculated in the size method. I can update my question but the code will become more complex. – Andrew No Apr 28 '16 at 18:56
1

I've definitely had this problem before. The takeaway lesson is that you should never call non-private methods in the Parent constructor so this doesn't happen

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • Unless they are final – djmorton Apr 28 '16 at 18:20
  • Technically the parent is calling an abstract method implemented in the child, but I see what you are saying. Is there a common work around? – Andrew No Apr 28 '16 at 19:03
  • @AndrewNo the work around you need to do what you were trying to do in a method call called after the object is constructed. This may leave the object initially in an invalid state, so you should throw an Exception if it used before it's been properly initialized – ControlAltDel Apr 28 '16 at 19:15
  • @ControlAltDel This is actually what I was coming to ask about. I just did that and it works, but this feels like a terrible design, but I don't know how else to do it. I will keep it the way you just suggested, but what is your opinion on this design? – Andrew No Apr 28 '16 at 19:18
  • @AndrewNo it's a kludge, obviously. The question is: How many parts of the program is this going to touch? How many people are going to be using / modifying this code? Otherwise, you could create a Factory for creating your objects so you can initialize them before anyone else uses them... Sometimes, you've just got to accept compromises – ControlAltDel Apr 28 '16 at 19:25
  • @ControlAltDel I know what I am going to do! I am going to make a static function that returns a new Instance. Not ideal, but less hacky than before. – Andrew No Apr 28 '16 at 19:35
1

Changing parent to take in the size as an argument is one option:

public Parent (int size)
{
    this.classDependentOnSize = new ClassDependentOnSize(size);
}

...

public Child (String selection, String... selectionArgs)
{
    super(selectionArgs.length);
    this.DBSelection = selection;
    this.DBSelectionArgs = selectionArgs;
}

Another option, which is a bit of a hack, is to have an init method that must be called after construction:

abstract class Parent
{
    private ClassDependentOnSize classDependentOnSize;

    public final void init()
    {
        this.classDependentOnSize = new ClassDependentOnSize(size());
    }

    public abstract int size ();
}

...

public Child (String selection, String... selectionArgs)
{
    this.DBSelection = selection;
    this.DBSelectionArgs = selectionArgs;
    init();
}

The right answer here is likely to change the structure your code, but, without more concrete details, I can't provide meaningful feedback as to how you want to go about that.

Ironcache
  • 1,719
  • 21
  • 33
  • I will update my question to better reflect the problem. The real code is so complex I did not want to overwhelm anyone with useless information but I have short changed myself. – Andrew No Apr 28 '16 at 18:57
  • Unfortunately the child must calculate the size. I can not determine the size before the child is initialized, which is a problem because the parent is initialized first. – Andrew No Apr 28 '16 at 19:04
  • As for your second option, that is what I was doing but you were right, it really does feel like a hack lol. – Andrew No Apr 28 '16 at 19:07