Circular Dependency in constructors and Dependency Injection

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.

class A {
final B b;
A(B b){
this.b = b;
}
}

class B {
final A a;
B(){
this.a = new A(this);
}
}

+---------+ +---------+
| A |<-----| B | | | | | | |----->| |
+---------+ +---------+

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 |<-----| B | | | | | +-+ | | | | +->|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 |<----| | | | +---+ +---------+ +---------+ class C { C(){ } } class A { final C c; A(C c){ this.c = c; } } class B { final A a; final C c; B(A a, C c){ this.a = a; this.c = 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.

Permalink | Links to this post |
The comments you read here belong only to the person who posted them. We do, however, reserve the right to remove off-topic comments.

10 comments:

Dale Emery said...

Could you post a small example?

David said...

What about circular references involving several classes. How do you apply your rule in these (more typical) cases?

Jonathan said...

I would really like to see an example too. It seems to me that the shorter of the two lists of methods is just going to be either class A or class B itself.

Jonathan said...

Is it supposed to be a list of methods in the class that reference the other object?

Mike Lee said...

Can I just AOL the example request. I'm a little confused by what you mean by this.

Also why would this be any harder to test than any other complex required dependency? Mock or stub the injected instance.

John said...

Really enjoying your posts Miško, each one makes me think :)

Howard said...

I've reached this from a different direction; when I've had a difficult service to test, I've split it into two cooperating services that can each be tested on their own.

HiveMind and T5 IoC are capable of co-injecting (via constructors) services; this is because what gets injected is a proxy. You'd have a problem trying to inject service implementation A into service implemenation B and vice versa at the same time, but with proxies, theres the extra abstraction.

Anyway, the mantra is: "Small is Beautiful".

Togge said...

An example of this (that I used on my blog):
Circular dependencies between classes can be solved by introducing a new class, e.g., if classes 'Alice' and 'Bob' has references to each other for exchanging messages, then a class 'Channel' should be introduced that they both will use to send and receive messages.

oy said...

WoW shares many wow gold of its features with previously launched games. Essentially, you battle with wow gold cheap monsters and traverse the countryside, by yourself or as a buy cheap wow gold team, find challenging tasks, and go on to higher aoc gold levels as you gain skill and experience. In the course of your journey, you will be gaining new powers that are increased as your skill rating goes up. All the same, in terms of its features and quality, that is a ture stroy for this.WoW is far ahead of all other games of the genre the wow power leveling game undoubtedly is in a league of its own and cheapest wow gold playing it is another experience altogether.

Even though WoW is a Cheap Wow Gold rather complicated game, the controls and interface are done in warhammer gold such a way that you don't feel the complexity. A good feature of the game is that it buy wow items does not put off people with lengthy manuals. The instructions bygamer cannot be simpler and the pop up tips can help you start playing the game World Of Warcraft Gold immediately. If on the other hand, you need a detailed manual, the instructions are there for you to access. Buy wow gold in this site,good for you, BUY WOW GOLD.

kiss said...

Weekends to peopleig2tmean that they can have a two-day wowgold4europe good rest. For example, people gameusdcan go out to enjoy themselves or get meinwowgoldtogether with relatives and friends to talk with each storeingameother or watch interesting video tapes with the speebiewhole family.
Everyone spends agamegoldweekends in his ownmmoflyway. Within two days,some people can relax themselves by listening to music, reading novels,or watchingogeworld films. Others perhaps are more active by playing basketball,wimming ormmorpgvipdancing. Different people have different gamesavorrelaxations.
I often spend weekends withoggsalemy family or my friends. Sometimes my parents take me on a visit to their old friends. Sometimesgamersell I go to the library to study or borrow some books tommovirtexgain much knowledge. I also go to see various exhibition to broadenrpg tradermy vision. An excursion to seashore or mountain resorts is my favorite way of spending weekends. Weekends are always enjoyable for me.