Circular Dependency in constructors and Dependency Injection
July 31st, 2008 | Published in Google Testing
by Miško Hevery
So you discovered dependency injection and GUICE and you are happily refactoring and writing new tests for you code until you come across this circular reference.
Hm, dependency injection says that you need to ask for your dependencies and so the resulting code will be:
But now we have a problem, we can't instantiate this (I know GUICE can through proxy, but it is not clean and it does not help us in tests). So the real problem in situation like this is mixing of concerns. One of the two objects is hiding another object C. Either A contains C or B contains C. To find out which one it is, list all of the methods in your class A and class B and. The shorter of the two lists is your hidden Class C.
Suppose B has the shorter list. We now extract all of the methods in B which are accessing the state of hidden C methods into a new object C like this:
So you discovered dependency injection and GUICE and you are happily refactoring and writing new tests for you code until you come across this circular reference.
class A {
final B b;
A(B b){
this.b = b;
}
}
class B {
final A a;
B(){
this.a = new A(this);
}
}
+---------+ +---------+
| A || |
+---------+ +---------+
Hm, dependency injection says that you need to ask for your dependencies and so the resulting code will be:
class A {
final B b;
A(B b){
this.b = b;
}
}
class B {
final A a;
B(A a){
this.a = a;
}
}
But now we have a problem, we can't instantiate this (I know GUICE can through proxy, but it is not clean and it does not help us in tests). So the real problem in situation like this is mixing of concerns. One of the two objects is hiding another object C. Either A contains C or B contains C. To find out which one it is, list all of the methods in your class A and class B and. The shorter of the two lists is your hidden Class C.
+---------+ +---------+
| A ||C| |
| |------+---->| | |
| | | +-+ |
+---------+ +---------+
Suppose B has the shorter list. We now extract all of the methods in B which are accessing the state of hidden C methods into a new object C like this:
+---------+
+---------+ | B |
| A || C |When you go through this exercise you will realize that the C was always an object in its own right but you have never thought about it that way, so the new code is actually better OO. From testing point of view you can now test each class in isolation.