How to handle variable initialization in certain circumstances

I have a class whose constructor looks something like this:

abstract class BasePanel extends JPanel { public BasePanel(A a) { // initializing fields from values passed to ctor this.a = a; // initializing gui components initializeComponents(); setupPanels(); concludeUiSetup(); } // stuff } 

In the constructor, the fields are first initialized, which should be initialized with the values ​​passed to the constructor. Then, the other methods needed to configure the UI are invoked in order. Two of these methods must be overridden in a subclass to customize their user interface.

Now consider the FooPanel class, which extends BasePanel . It requires a few more initialization parameters in its constructor.

 class FooPanel extends BasePanel { public FooPanel(A a, B b) { super(a); this.b = b; } @Override public void initializeComponents() { super.initializeComponents(); // I require b here, but oops, b is not initialized at this point, and so // this will throw NPE. someTextField.setText(b.get()); } // stuff } 

initializeComponents requires b here, which, unfortunately, is not initialized at this point.

What would be a suitable way to restructure this code so that:

  • Required fields are set until necessary.
  • code that uses FooPanel (and other panels) is not heavily overwhelmed by this change.

Any help is greatly appreciated. Thanks.

+1
source share
2 answers

You should not call overridden methods from the constructor. In this case, you must define a constructor that initializes only the instance fields, and initialize the GUI in overridable initialize () mode, which is not called from the constructor.

So, to build a FooPanel, follow these steps:

 FooPanel p = new FooPanel(a, b); p.initialize(); 

And if you do not force all FooPanel clients to do this, you define the private constructor and provide the factory method:

 public static FooPanel create(A a, B b) { FooPanel p = new FooPanel(a, b); p.initialize(); return p; } 
+7
source

Basically, try to avoid invoking virtual (i.e., redefined) methods inside constructors. This causes just such a problem. If you intend to invoke a virtual method in the constructor, you need to document it - and perhaps do not call elsewhere. Such a method must be written to process an object that is not yet fully initialized, which puts it in an inconvenient place.

It is difficult to find out more specific recommendations to give without additional information, but I also urge you to take the composition by inheritance, where possible, or at least always consider it, and decide on the most elegant approach.

If you really want to inherit here, do you really need initializeComponents at all? Can each class do its initialization inside its own constructor without relying on anything from its subclass state?

+5
source

Source: https://habr.com/ru/post/915870/


All Articles