Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize classes dependent on each other, in Java?

Say I have the class signatures

Class1(Class2 c);
Class2(Class1 c);

How do I initialize both?

like image 606
mchlsctt Avatar asked Dec 06 '12 01:12

mchlsctt


2 Answers

For one of the classes, you don't provide the reference in the constructor, but you can use a set-method instead. Initializing them both dependent on each other when none of them previously exists seems difficult.

class Foo {
    private Bar bar;
    public Foo(Bar bar) {
        this.bar = bar;
    }
}

class Bar {
    private Foo foo;
    setFoo(Foo foo) {
        this.foo = foo;
    }
}


Bar bar = new Bar();
Foo foo = new Foo(bar);
bar.setFoo(foo);

Also note that there might be better solutions to this. Such as using an Observer-pattern, it all depends on how you plan on using your objects.

like image 103
Simon Forsberg Avatar answered Sep 18 '22 23:09

Simon Forsberg


Your problem does not make much sense. If each class require the other one to initialize, then you really have to rethink how your classes are designed in the first place.

You might consider having one of the class creating the other one itself, instead of having to specify it in the constructor. For example :

class Class1 {
    private Class2 c2;
    public Class1() {
        this.c2 = new Class2(this);
    }
}

class Class2 {
    private Class1 c1;
    public Class2(Class1 c) {
        this.c1 = c;
    }
}

Or create setters and allow them to be created in an "uninitialized" state (that can throw exceptions if not properly setup). For example :

class Class1 {
    private Class2 c2;
    public void setClass2(Class2 c) {
        this.c2 = c;
    }
    public void doSomething() {
        if (null == c2) throw new IllegalStateException();
        // ...
    }
}

class Class2 {
    private Class1 c1;
    public void setClass1(Class1 c) {
        this.c1 = c;
    }
    public void doSomething() {
        if (null == c1) throw new IllegalStateException();
        // ...
    }
}

// somewhere else....
Class1 c1 = new Class1();
Class2 c2 = new Class2();
c1.setClass2(c2);
c2.setClass1(c1);

Also, if each instances need to be double-linked to each other, you should check that they are indeed owned by the right objects, otherwise you might create bad references... which this is exactly why it is a bad design in the first place. Consider this :

Class2 c2 = new Class2(new Class1());

and you might think it is a clever construct, however c2.getClass1().getClass2() != c2.

Neither does it guarantee that c1.getClass2() == c2 && c2.getClass1() == c1 in both cases above.

Your classes should check that the back reference is the proper one, and you can't achieve this properly with either methods!

To solve this chicken and the egg problem, you'll need some kind of factory method, or a third class. Consider this :

abstract class Class1 {
    public abstract Class2 getClass2();
}

abstract class Class2 {
    public abstract Class1 getClass1();
}

public Class3 {
    private Class1 c1;
    private Class2 c2;
    public Class3() {
        c1 = new Class1_Impl();
        c2 = new Class2_Impl();
    }
    public Class1 getClass1() { return c1; }
    public Class2 getClass2() { return c2; }
    private class Class1_Impl extends Class1 {
         public Class1 getClass2() { return c2; }
    }
    private class Class2_Impl extends Class2 {
         public Class1 getClass1() { return c1; }
    }
}

// and later on...
Class3 c3 = new Class3();
Class1 c1 = c3.getClass1();
Class2 c2 = c3.getClass2();

And with this, you are guaranteed that c1.getClass2() == c2 && c2.getClass1() == c1 always.


If you are still reading, then you are on the enlightenment track. If you can see what are the consequences of this class design, then you will understand how circular dependency is an anti-pattern and should be avoided.

However, your question is not specific enough for me to fully give you a more proper way to fix your problem in a clean and better way.

like image 33
Yanick Rochon Avatar answered Sep 18 '22 23:09

Yanick Rochon