The Circular Dependency anti pattern occurs when two modules depend directly or indirectly on each other to work. It is usually considered acceptable to have some circular dependencies between domain classes and objects. In the real world, circular dependencies are very common. However, if there are circular dependencies between modules such as packages, that is considered an anti pattern. This is closely related to the Acyclic dependencies principle.
Some IDEs like Visual Studio actively disallow such dependencies between packages but others allow it.
Imagine that we have divided our system into a model and a gui package. The model package contains the domain classes while the gui package contains the GUI classes.
In a bad design, we could have a circular dependency between these packages. The gui package may need knowledge of the domain classes in the model package in order to be able to display information appropriately. The model package may tell the gui package to update the display when changes occur. This is obviously a bad design for several reasons and the model package should never really know about the GUI. It is also an example of the Circular Dependency anti pattern.
- Tight coupling between two modules in a circular dependency makes it more difficult to reuse one of them in another context.
- Maintainability is decreased as changes in one module may propagate to the other module and back in a kind of domino effect.
- Other side effects like memory leaks are possible because circular dependencies can impact automatic garbage collection.
Related design heuristics
Anemic Domain Model | BaseBean | Call super | Circle-ellipse problem | Circular dependency