2

Evening everyone.

I seem to have hit an odd problem when trying to pass an object to another objects constructor who's constructor also relies on the object it's being passed to.

For instance, take the example below:

ToolBar myToolBar = new ToolBar(webPanel);
WebPanel webPanel = new WebPanel(myToolBar);

However when constructing ToolBar it returns a NullPointerException. Ofcourse that's because webPanel isn't constructed yet and it requires it.

Both of the decelerations and initialization must remain in the same class (called BuildUI) since it's where I set up the properties. (It also doesn't make sense for a ToolBar to create a webPanel object and vice versa).

I'm also not sure if that's even good programming practice, since both objects require references to each other.

Any advice here is much appreciated. Thanks, Tom.

Emphacy
  • 79
  • 1
  • 7
  • 1
    Why don't you instantiate one class, then the second and after use a `set()` type of method to pass the reference you need? – A--C Dec 10 '12 at 21:54
  • 1
    Why do you have this circular dependency? What are you trying to accomplish with this? – thedan Dec 10 '12 at 21:54
  • 6
    I think this is just a sign of bad design - change it so this isn't needed. – Gareth Latty Dec 10 '12 at 21:54
  • 2
    _I'm also not sure if that's even good programming practice_... not only bad practice, also wrong. – vainolo Dec 10 '12 at 21:56
  • I have seen very similar circular reference with some layout managers in Swing ... couldn't guess the reason: `this.cntnrPnl = new JPanel(); this.cntnrPnl.setLayout(new BoxLayout(this.cntnrPnl, BoxLayout.Y_AXIS));` – amphibient Dec 10 '12 at 21:58
  • So by that token a doubly linked list is a bad idea or are reverse references only bad across different types? – Miserable Variable Dec 10 '12 at 21:58
  • @MiserableVariable -- not at all is a doubly linked list is bad idea, only setting the link twice explicitly. see another thread i just started: http://stackoverflow.com/questions/13810075/java-swing-layout-manager-circular-reference – amphibient Dec 10 '12 at 22:06
  • @thedan - I can't find a way around the circular dependency. Take a web browser for instance. The Toolbar modifies the Webpanel (clicking the back button for example) and actions you take in the Webpanel (clicking links...) modify the buttons/ searchBar on the Toolbar. – Emphacy Dec 10 '12 at 22:23

7 Answers7

3

This will lead to problems as you can see. Instead of this approach, you can use the setter-getter method approach where you construct the object with a default constructor such as

ToolBar myToolBar = new ToolBar();
WebPanel webPanel = new WebPanel();

and then use the setter methods to set the required instance variables which are required for the object to be fully constructed.

myToolBar.setWebPanel(webPanel);
webPanel.setToolBar(myToolBar);
CodeDreamer
  • 444
  • 2
  • 8
2

This seems like a nice example for a vicious circle.

I would suggest breaking the circle by using a separate method, e.g. addToolbar(), to add the other object to one of the classes, rather than a constructor. You would only need to add a few checks to avoid illegal object states, if that method has not been called:

class WebPanel {
    public void addToolbar(Toolbar toolbar) {
        ...
    }
}
...
class ToolBar {
     public ToolBar(WebPanel parent) {
         ...
     }
}
...
WebPanel webpanel = new WebPanel();
webpanel.addToolbar(new Toolbar(webpanel));

In general, it is preferred for "child" objects to take the parent object as a constructor argument and then be added to the parent via a method call, rather than the other way around. In a UI the outer elements are parents to their contents - in your case I would probably expect a WebPanel to contain - and thus be a parent of - a ToolBar object...

thkala
  • 84,049
  • 23
  • 157
  • 201
1

I've have objects reference each-other before. I.e. in a game an object might contain a reference to it's cell, and the cell can contain a reference to the object.

You just have to be careful regarding how you create your objects.

Nothing says that they have to both be passed into each-others constructors, in-fact you can create both objects, and then in a different method, have them reference each-other.

It's also not an uncommon practice to check if a value is null before using it(but only do this is the value actually has an excuse to ever be null.)

1

Mmn.. what you could do is create a model object that wraps around your toolbar and WebPanel.

public class SomeModel{
  WebPanel panel;
  Toolbar toolbar;
}

Or you could create your toolbar object.. and in the constructor of the toolbar create your webpanel

public WebPanel()
{
   this.toolbar= new Toolbar(this); 
}
webPanel = new WebPanel();
webPanel.getToolbar() ;

Ok that was cheating lmao It depends whether one is a composite object of another; although I think the Model way is better.. no circular reference.

Lews Therin
  • 10,907
  • 4
  • 48
  • 72
  • Both ideas make sense; however, the second seems to hardcode an object, which ought to be injected into it during initialization............IMO. – Kneel-Before-ZOD Dec 10 '12 at 22:05
  • It should work......also, I think the OP needs to give an example of such situation; otherwise, common dictates that one will depend on the other, and whichever one is the dependent object needs to inject the independent object into it. – Kneel-Before-ZOD Dec 10 '12 at 22:15
  • It would work if I create toolbar without passing the WebPanel object.. `new WebPanel(new Toolbar())`.. but if the OP wants to use bad design.. what you get is more bad design :( – Lews Therin Dec 10 '12 at 22:16
0

Maybe if you declare first

WebPanel webPanel = new WebPanel(myToolBar);

and then

ToolBar myToolBar = new ToolBar(webPanel);

The object must exist first to be passed.

user1822263
  • 105
  • 1
  • 7
  • 13
0

There are multiple ways to do it; I usually prefer to pass parameter to one of the two and have it call a setter method in the other:

class ToolBar {
  void setWebPanel(WebPanel wp) { 
    _wp = wp; 
  }
  ....
}

class WebPanel {
  WebPanel(ToolBar t) {
    _t = t;
    _t.setWebPanel(this);
  }
}
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
0
ToolBar myToolBar = new ToolBar(webPanel);
WebPanel webPanel = new WebPanel(myToolBar);

new Toolbar() instead of new Toolbar(webPanel)

then inside WebPanel(Toolbar toolbar) constructor do toolbar.add(this) where add(WebPanel webPanel) method is defined in Toolbar.

prsadrian
  • 23
  • 5