Kotlin

Converting a Cyclic Dependency into a Directed Dependency

So, this came out over a month late… Woops.

This is definitely not my original idea in the least. I wish I knew where I originally found this so I could share that, but seeing that I can’t find it and I haven’t seen it anywhere else, I’d like to share this idea so it can become more well-known.

What is a cyclic dependency? It is one of mutual dependency, where one class depends on another that also depends on the first one, as shown below.

cyclic dependency

There can also be more classes in between as shown below, where it just eventually circles back to the beginning.

cyclic dependency

You probably know this, but in case you don’t, you should know that you don’t want these types of situations. They hurt the understandability of your system and make it harder for garbage collectors to clean them up when they’re done. There are probably more reasons, too, but I’ve never paid much attention to this, and it seems that as a whole, the community knows that they should avoid cyclic dependencies but doesn’t do much to avoid it.

Anyway, what you’re looking for is a nice acyclic directed graph of dependencies as shown below, where all the arrows point down.

cyclic dependency

So, how do we go from this

cyclic dependency

To an acyclic directed graph? What would that graph look like?

Well, it would look like this!

cyclic dependency

You take the part of the class that is depended on by the other class and extract it. Do this for both classes, and your problem is solved!

With these super vague graph images, it may be difficult to really see how this can actually be done, so I’ll give you a really simple code example (written in Kotlin and Python!). It should help you get started when breaking apart your cyclic dependencies.

class A {
   var b: B? = null
   var _observed: Int = 0
   var observed: Int
       get() = _observed
       set(value) {
           _observed = value
           b?.alert()
       }

   fun alert(): Unit {
       println("A.alert")
   }

   fun doSomething(): Unit {
       alert()
   }
}

class B {
   var a: A? = null
   var _observed: Int = 0
   var observed: Int
       get() = _observed
       set(value) {
           _observed = value
           a?.alert()
       }

   fun alert(): Unit {
       println("B.alert")
   }

   fun doSomething(): Unit {
       alert()
   }
}

 

class A:
   def __init__(self):
       self.b: B = None
       self._observed: int = 0

   @property
   def observed(self):
       return self._observed

   @observed.setter
   def observed(self, value):
       self._observed = value
       self.b.alert()

   def alert(self):
       print("A.alert")

   def doSomething(self):
       self.alert()

class B:
   def __init__(self):
       self.a: A = None
       self._observed: int = 0

   @property
   def observed(self):
       return self._observed

   @observed.setter
   def observed(self, value):
       self._observed = value
       self.a.alert()

   def alert(self):
       print("B.alert")

   def doSomething(self):
       self.alert()

The two classes are almost exactly the same, but that doesn’t really matter. What matters is that the dependent parts can be extracted. What parts of type B does A depend on? And vice versa? Each class depends on the other’s alert() method. So let’s extract those out:

class AAlerter {
   fun alert(): Unit {
       println("A.alert")
   }
}

class BAlerter {
   fun alert(): Unit {
       println("B.alert")
   }

}

 

class AAlerter:
   def alert(self):
       print("A.alert")

class BAlerter:
   def alert(self):
       print("B.alert")

Now the other classes can depend on these

class A (var a: AAlerter, var b: BAlerter) {
   var _observed: Int = 0
   var observed: Int
       get() = _observed
       set(value) {
           _observed = value
           b.alert()
       }

   fun doSomething(): Unit {
       a.alert()
   }
}

class B (var a: AAlerter, var b: BAlerter){
   var _observed: Int = 0
   var observed: Int
       get() = _observed
       set(value) {
           _observed = value
           a.alert()
       }

   fun doSomething(): Unit {
       b.alert()
   }
}

 

class A:
   def __init__(self, a: AAlerter, b: BAlerter):
       self.a = a
       self.b = b
       self._observed: int = 0

   @property
   def observed(self):
       return self._observed

   @observed.setter
   def observed(self, value):
       self._observed = value
       self.b.alert()

   def doSomething(self):
       self.a.alert()

class B:
   def __init__(self, a: AAlerter, b: BAlerter):
       self.a = a
       self.b = b
       self._observed: int = 0

   @property
   def observed(self):
       return self._observed

   @observed.setter
   def observed(self, value):
       self._observed = value
       self.a.alert()

   def doSomething(self):
       self.b.alert()

You may notice that, due to the cyclic dependencies, there was no way to create instances of the original classes without null/None because each one would require an instance to exist in order to make it.

Now, it’s possible to create an instance where the constructor takes in all of the fields without any temporary nulls/Nones.

Outro

As I said before, I realize that this is a super simple example, and I don’t expect it to make you into experts on removing cyclic dependencies. What I do expect is that you now have your mind wrapped around the basics and can start trying to take apart some of these when you see them.

I will admit that there is at least one “kind” of cyclic dependency that this doesn’t fix: A child pointing back to its parent. For example, you have a FilingCabinet with a list of Files in it, and those Files also have a pointer back to the FilingCabinet they’re in if you ever need a way to traverse back up the tree when you don’t know the original already.

The advice I’ve seen on this is to lose the link going back to the parent and instead put in a method that does some kind of lookup to find the parent. This is silly; it still has the cyclic dependency; it’s just that the dependency is either one step further removed (for a fully in-memory, in-language lookup) or is pulled into a different kind of system (for something like a database lookup).

I recommend either trying to make it so that the code doesn’t need to go back up the tree or that the parent is passed in along with the child, possibly in some sort of custom parent-child pair type.

Published on Java Code Geeks with permission by Jacob Zimmerman, partner at our JCG program. See the original article here: Converting a Cyclic Dependency into a Directed Dependency

Opinions expressed by Java Code Geeks contributors are their own.

Jacob Zimmerman

Jacob is a certified Java programmer (level 1) and Python enthusiast. He loves to solve large problems with programming and considers himself pretty good at design.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button